Skip to content

Structural Satisfaction Reflection

Accepted

Accepted for the V1 structural satisfaction predicate and metadata APIs.

Structural satisfaction reflection describes whether one concrete type satisfies one inspectable structural constraint Type in one lookup scope.

T.satisfaction(Shape, scope) Type.Satisfaction!Type.SatisfactionError

This answers:

  • whether concrete type T has the visible fields and functions required by Shape
  • which concrete declarations matched each requirement
  • which requirements failed, and why
  • which scope controlled visibility

It does not run arbitrary user-defined comptime predicates, prove semantic contracts, expose runtime interfaces, or define layout compatibility.

Lookup API

Structural satisfaction has a predicate API and a metadata API:

T.satisfies(Shape, scope: ?Scope = null) Type.Predicate

T.satisfaction(Shape, scope: ?Scope = null) Type.Satisfaction!Type.SatisfactionError

The optional scope argument defaults to null, not Scope.caller(). The called API resolves null to Scope.caller() in its body before delegating. See Predicate Reflection for scope forwarding and predicate facts.

T.satisfies(Shape) returns false when the shape does not match. T.satisfaction(Shape) reports structured errors for failed requirements.

V1 requirements:

  • T must be a concrete type.
  • Shape must be a structural constraint Type.
  • Shape must expose inspectable structural requirements through Type reflection.
  • Shape may be produced by satisfies(...), mutable_fields(...), or another comptime function that builds an equivalent structural constraint Type through compiler-provided primitives.
  • Shape must not be a semantic contract, contract intersection, dyn C, concrete type, or arbitrary comptime bool predicate.

Constraint Metadata Boundary

Sema consumes the structural constraint Type and its metadata, not the name of the function that produced it.

The canonical V1 constructors are:

  • satisfies(...) for read-only field and function shape requirements
  • mutable_fields(...) for assignable field-slot requirements

Prelude and user code may perform ordinary comptime validation while building a structural constraint. That validation may reject bad input or assemble reusable shape metadata. It does not become a reusable .satisfies fact unless the final value is an inspectable structural constraint Type.

Arbitrary comptime checks in generic factories remain ordinary comptime logic. A check that returns bool can accept or reject code, but it does not create narrowing facts. A custom function can preserve .satisfies facts only by returning or composing compiler-produced Type.Predicate values; facts are not forgeable.

Checking whether one structural constraint implies another is deferred.

Requirement Metadata

The declarations in this page describe public metadata members exposed through Type; they use source-shaped const Name = struct { ... } bindings rather than invalid qualified declarations such as struct Type.Name { ... }.

Concrete declaration reflection is separate from constraint requirement reflection:

T.fields()
T.inherent_functions()

Shape.required_fields()
Shape.required_functions()

Field requirements use the common field-access model:

const FieldAccess = enum {
  read,
  readwrite,
}

const FieldRequirement = struct {
  name: []const u8
  ty: Type
  access: Type.FieldAccess
}

satisfies(...) produces read field requirements. mutable_fields(...) produces readwrite field requirements. A readwrite requirement includes readable access; reflection does not duplicate a separate read requirement for the same field.

Function requirements describe source-visible callable shape:

const FunctionRequirement = struct {
  name: []const u8
  signature: Type.Function
  source: ?SourceLocation
  docs: ?[]const u8
}

Function requirement matching uses the same function-shape semantics as function declaration reflection. See Function Reflection.

Satisfaction Metadata

Type.Satisfaction should describe the visible structural match as ordinary deterministic comptime data:

const Satisfaction = struct {
  ty: Type
  shape: Type
  scope: Scope

  fields: []const Type.SatisfiedField
  functions: []const Type.SatisfiedFunction
}

const SatisfiedField = struct {
  requirement: Type.FieldRequirement
  field: Type.Field
}

const SatisfiedFunction = struct {
  requirement: Type.FunctionRequirement
  function: Type.FunctionDecl
}

Successful metadata contains one match per active requirement in deterministic requirement order. Extra fields and functions on T are ignored.

Structural satisfaction inspects inherent and source-visible shape, not semantic contract operations available through method lookup. Private members count only in scopes where ordinary code can access them. Source-visible builtin or synthetic members, such as slice .ptr and .len, may satisfy requirements when their reflected metadata matches.

Field requirements are name-based and use ordinary assignability to the required field type. A read requirement is satisfied by a readable const or mutable field. A readwrite requirement requires a field-like member that can be assigned through ordinary field assignment.

Function requirements are name-based and signature-checked. V1 does not define overload sets; if visible lookup for a function requirement is ambiguous, satisfaction fails with an ambiguity error.

Errors

Failed metadata lookup returns structured errors:

const SatisfactionErrorKind = enum {
  not_concrete_subject,
  not_structural_shape,
  not_inspectable_shape,
  semantic_contract_target,
  concrete_type_target,
  missing_field,
  field_access_mismatch,
  field_type_mismatch,
  missing_function,
  function_signature_mismatch,
  ambiguous_function,
}

const SatisfactionError = struct {
  kind: Type.SatisfactionErrorKind
  subject: Type
  shape: Type
  scope: Scope
  field_requirement: ?Type.FieldRequirement
  function_requirement: ?Type.FunctionRequirement
  candidates: []const Type.SatisfactionCandidate
}

For field and function failures, the relevant requirement field is present. Candidate lists contain visible candidates only and are deterministic. Missing requirements may include visible near misses when sema can report them deterministically.

const SatisfactionCandidate = struct {
  name: []const u8
  ty: Type
  source: ?SourceLocation
  visibility: Visibility
  origin: Type.DeclOrigin
}

Predicate Facts

When T.satisfies(Shape) succeeds, the returned predicate carries a .satisfies fact for (T, Shape, scope).

In a comptime if condition or declaration guard, that true fact makes the structural requirements from Shape available in the branch or guarded declaration body. Facts are lexical and branch-local, and they are discarded when the predicate is coerced to bool.

Type.Satisfaction metadata is for diagnostics, tooling, and comptime logic. The reusable narrowing fact comes from the predicate API.

Boundaries

Deferred:

  • constraint-to-constraint implication
  • user-defined custom fact producers
  • negative structural facts
  • structural overload-set matching
  • runtime structural interfaces or erased structural objects
  • layout compatibility from structural satisfaction
  • exposing private or non-visible candidates outside the lookup scope