Skip to content

Add type checking to Laurel resolution pass#1121

Merged
leo-leesco merged 207 commits into
reviewed-kbd-will-merge-to-mainfrom
keyboardDrummer-bot/issue-1120-type-checking
Jun 18, 2026
Merged

Add type checking to Laurel resolution pass#1121
leo-leesco merged 207 commits into
reviewed-kbd-will-merge-to-mainfrom
keyboardDrummer-bot/issue-1120-type-checking

Conversation

@keyboardDrummer-bot

Copy link
Copy Markdown
Collaborator

Summary

Adds type checking to Laurel's Resolution.lean as requested in #1120.

Changes

  • resolveStmtExpr now returns ResolveM (StmtExprMd × HighTypeMd) — both the resolved expression and its synthesized type.

  • Type checks added:

    • Boolean conditions in if/while/assert/assume must be TBool
    • Arithmetic/comparison operands must be numeric (TInt, TReal, TFloat64)
    • Logical operands (And, Or, Not, Implies, etc.) must be TBool
    • Static call argument types must match parameter types
    • Instance call argument types must match parameter types (skipping self)
    • Assignment value type must match target type (single-target only)
    • Functional procedure body type must match declared output type (transparent bodies only)
  • Diagnostics, not hard failures — type mismatches are reported via ResolveState.errors and compilation continues.

  • Cascading error prevention:

    • Unknown types are compatible with everything
    • UserDefined types skip strict assignability checks (subtype/inheritance relationships are not tracked during resolution)
    • TVoid types skip assignment/output checks (statements like return/while don't produce values in the expression sense)
    • MultiValuedExpr types skip assignability checks (arity mismatch already reported separately)
    • Kind-mismatched type references (e.g., using a variable name as a type) produce Unknown to avoid cascading
  • computeExprType in LaurelTypes.lean is unchanged — it continues to work alongside the new type checking.

  • Callers updated to use the returned type from resolveStmtExpr (e.g., resolveBody, resolveProcedure, resolveInstanceProcedure, resolveConstant, resolveTypeDefinition).

Testing

All existing tests pass (lake build StrataTest — 592 jobs successful).

Closes #1120"

- Change resolveStmtExpr to return (StmtExprMd × HighTypeMd)
- Add type checks for:
  - Boolean conditions in if/while/assert/assume
  - Numeric operands in arithmetic/comparison operations
  - Boolean operands in logical operations
  - Argument types matching parameter types in static calls
  - Argument types matching parameter types in instance calls
  - Assignment value type matching target type
  - Function body type matching declared output type
- Report type mismatches as diagnostics (compilation continues)
- Handle cascading errors: Unknown types are compatible with everything,
  UserDefined types skip strict checking (subtype relationships not tracked),
  void types skip assignment checks (statements don't produce values)

Closes #1120
TCore is a pass-through type from Core that should not be checked
during Laurel resolution. Without this, two identical TCore types
(e.g. 'Core Any') would fail highEq (which has no TCore case) and
produce spurious 'Type mismatch' diagnostics.
@keyboardDrummer

Copy link
Copy Markdown
Contributor

@keyboardDrummer-bot can you add a test that confirms various type checking errors are reported?

Comment thread Strata/Languages/Laurel/Resolution.lean Outdated
Derive expected output count from the RHS type (MultiValuedExpr
gives the arity, otherwise 1) instead of re-looking up the procedure.
This ensures LHS and RHS arity always match for assignments.
Tests confirm that the following type errors are reported:
- Non-boolean condition in if/assert/assume/while
- Non-boolean operand in logical operators (&&)
- Non-numeric operand in comparisons (<)
- Assignment type mismatch (int := bool)
- Function return type mismatch
- Static call argument type mismatch
- Add checkSingleValued helper that detects MultiValuedExpr types
  used in expression position (e.g., as operands to PrimitiveOp)
- Emit error: "Multi-output procedure '<name>' used in expression position"
- Add ResolutionTypeTests.lean with test for assert multi(1) == 1
Comment thread Strata/Languages/Laurel/Resolution.lean Outdated
…naturally

Instead of a dedicated 'Multi-output procedure used in expression position'
error, multi-output calls in expression position now produce standard type
mismatch errors like 'expected int, but got (int, int)'.

- Remove checkSingleValued function and its call in PrimitiveOp
- Remove MultiValuedExpr skip in checkAssignable
- Add Eq/Neq operand compatibility check
- Add formatType helper for nice MultiValuedExpr formatting
- Skip assignment type check when arity already mismatches

@tautschnig tautschnig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. checkBool and checkNumeric pass-through for UserDefined (lines 381, 388). The comment says "constrained types may wrap bool / numeric", which is fair for constrained subtypes, but the check is by kind rather than by wrapped base type: a Color user type will silently pass checkBool, and Dog will silently pass checkNumeric. In practice the downstream type-erasure path may catch these later, but the point of type checking here is to catch them early. Two options, either is fine:
  • Inspect the resolved UserDefined target to see whether it's .constrainedType wrapping a compatible base, and only pass it through in that case.
  • Keep the current permissive behaviour but add a comment and a test that explicitly documents "Color in if pos slot silently passes — known limitation, tracked under #…".
  1. checkAssignable treats any UserDefined / TCore pair as compatible (lines 399–402). This is the deliberate "subtype relationships not tracked here" trade-off, noted in the PR body. It means var x: Dog := new Cat and var x: CoreA := ∅CoreB-typed RHS both silently succeed. Worth a regression test that asserts no diagnostic is emitted for such cases, as a paper trail for the known limitation (so that when someone later does track subtyping, the test flips from "passes without complaint" to "correctly rejects").

  2. Eq / Neq uses checkAssignable source rhsTy lhsTy (line 571) — asymmetric for a symmetric operator, and the resulting diagnostic reads "Type mismatch: expected '{rhsTy}', but got '{lhsTy}'" which misleadingly frames the LHS as "wrong". For 1 == "hello" the user sees "expected 'string', but got 'int'" — technically accurate under the checker's internal view but confusing. Consider either (a) dropping the check for Eq/Neq entirely and relying on the caller to ensure the operands are in the same comparable category, or (b) rewording the diagnostic message for the symmetric case: "operands of '==' have incompatible types '{lhsTy}' and '{rhsTy}'".

  3. PrimitiveOp.StrConcat has no operand check (inside the match op with at around line 575). If someone writes 1 ++ "hello" it slides through. Trivial to add: for aTy in argTypes do checkAssignable source { val := .TString, source := source } aTy.

  4. Quantifier body type is assumed .TBool (line 605) without a check that it actually is. forall x: int . x (body of type int) silently passes. Trivial to add: checkBool body'.source bodyTy.

  5. Arity guard valueTy.val != HighType.TVoid (line 507) skips the check when the RHS is void. Correct for statement RHS like return / while, but relies on the checker never mis-tagging a value expression as void. Worth a comment spelling out why the void guard is there so a future refactor doesn't accidentally loosen it.

  6. Functional procedure body-type check is isFunctional && body'.isTransparent (lines 691 and 731). The duplicated block between resolveProcedure and resolveInstanceProcedure is identical modulo the surrounding scope — easy to factor into a checkFunctionalBodyType helper.

Maintainability / refactoring:

  • Repeated pattern do let (e', _) ← resolveStmtExpr a.val; pure e'. It appears at 15+ sites (invariants, decreases, preconditions, invokeOn, constant initializers, type-definition constraint/witness, field-target recursion, etc.). A one-line helper:

    private def resolveStmtExprExpr (e : StmtExprMd) : ResolveM StmtExprMd := do
      let (e', _) ← resolveStmtExpr e; pure e'

    would compress each site to a one-liner and make it obvious which callers are intentionally discarding the type. See inline on checkAssignable.

  • Two test files with confusingly similar names. ResolutionTypeCheckTests.lean (9 cases) and ResolutionTypeTests.lean (1 case) both target resolution-time type checking. The naming distinction is TypeCheck vs Type which is not self-explanatory. Consider consolidating — either rename one to something unambiguous (e.g., ResolutionMultiOutputTests.lean) or merge into a single file with clearly named sections. See inline.

Test coverage gaps: the nine scenarios in ResolutionTypeCheckTests.lean cover scalar operations well. Four additions would strengthen the suite materially:

  • Instance call argument mismatch. The static-call case is covered; .InstanceCall uses the same checkAssignable loop with the self parameter stripped, which is a logically distinct code path at line 611 and deserves its own test.
  • Constant initializer mismatch. resolveConstant threads through the new checker at line 808 but there's no test for const x: int := true.
  • User-defined type pass-through documentation. var x: Dog := new Cat should pass silently today. A test that asserts "no diagnostic emitted" pins the known limitation — when the hierarchy check lands later, this test flips and is a reminder to update.
  • Assignment target-count mismatch. The arity check at line 505 was the heart of review thread #1 but there's no test like procedure multi() returns (a: int, b: int) opaque; … var x := multi() (one LHS, two RHS). Worth a fixture.

Proof-coverage suggestions. Mostly meta-code, but four invariants are worth stating:

  • Soundness. If resolveStmtExpr e returns (e', τ) and no diagnostic is emitted, then e' is well-typed at τ under some formal type system. Stating this formally would require a semantic model for Laurel types; as a lighter-weight intermediate, prove type consistency: the returned τ for a LiteralInt is always .TInt, etc. — which is immediate from the code but stating it pins the correspondence.
  • Cascade suppression. For every expression e, if any sub-expression has type .Unknown, then no new diagnostic is emitted at e's level due to that sub-expression. This formalises the intent of the Unknown wildcards in checkBool / checkNumeric / checkAssignable — forget one of those wildcards in a future extension and the invariant fails.
  • Arity-match completeness. targets'.length != expectedOutputCount ∧ valueTy ≠ .TVoid → arity diagnostic is emitted. Test #1's concern, formalised.
  • UserDefined symmetry. checkAssignable _ tyA tyB is currently not symmetric in general (normal types use highEq), but is symmetric whenever either operand is UserDefined/TCore/Unknown. A small lemma documenting when symmetry holds would make the asymmetric case in Eq/Neq (observation 3) less of a UX footgun.

Inline comments on the two highest-impact items below.

Comment thread Strata/Languages/Laurel/Resolution.lean Outdated
Comment thread StrataTest/Languages/Laurel/ResolutionTypeTests.lean Outdated
@leo-leesco leo-leesco self-assigned this May 6, 2026
keyboardDrummer-bot and others added 16 commits May 6, 2026 17:07
…solidate tests

- Add checkComparable helper for symmetric Eq/Neq error messages
  ("Operands of '==' have incompatible types 'X' and 'Y'")
- Extract resolveStmtExprExpr helper to reduce repeated pattern
- Add constant initializer type check in resolveConstant
- Merge ResolutionTypeTests.lean into ResolutionTypeCheckTests.lean
- Add tests: equality type mismatch, assignment target count mismatch,
  UserDefined pass-through (documents known limitation)
- Update checkAssignable doc comment to mention TCore types
first implementation : blocks
discards the type synthesized
general design
rules (one section per rule)
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
VerifyMetricsCorpusTest (poly procedures, generic composites/methods/inheritance/upcast/
field-tvar, generic datatypes), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 19, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest. Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 20, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest, and AbstractToConcreteTreeTranslatorTest
(AST→concrete→AST round-trips for the new generic emit productions; writing them surfaced
and fixed a formatter bug where the `prec(80)` `appliedType`/`newTypeArgs` ops were
parenthesized into non-re-parseable text — `(Box<int>)`, `new Box(<int>)` — corrected via
`:0` annotations on the `typeAnnotation`/`new` references). Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 20, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest, and AbstractToConcreteTreeTranslatorTest
(AST→concrete→AST round-trips for the new generic emit productions; writing them surfaced
and fixed a formatter bug where the `prec(80)` `appliedType`/`newTypeArgs` ops were
parenthesized into non-re-parseable text — `(Box<int>)`, `new Box(<int>)` — corrected via
`:0` annotations on the `typeAnnotation`/`new` references). Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 20, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest, and AbstractToConcreteTreeTranslatorTest
(AST→concrete→AST round-trips for the new generic emit productions; writing them surfaced
and fixed a formatter bug where the `prec(80)` `appliedType`/`newTypeArgs` ops were
parenthesized into non-re-parseable text — `(Box<int>)`, `new Box(<int>)` — corrected via
`:0` annotations on the `typeAnnotation`/`new` references), and
Core/Tests/PolyProcFreshenTest (Core-layer regression tests for CallElim per-call-site
type-var freshening — multi-instantiation verifies, the soundness twin fails at the exact
obligation, and the abort-masking ship-blocker is pinned by obligation label). Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 20, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest, and AbstractToConcreteTreeTranslatorTest
(AST→concrete→AST round-trips for the new generic emit productions; writing them surfaced
and fixed a formatter bug where the `prec(80)` `appliedType`/`newTypeArgs` ops were
parenthesized into non-re-parseable text — `(Box<int>)`, `new Box(<int>)` — corrected via
`:0` annotations on the `typeAnnotation`/`new` references), and
Core/Tests/PolyProcFreshenTest (Core-layer regression tests for CallElim per-call-site
type-var freshening — multi-instantiation verifies, the soundness twin fails at the exact
obligation, and the abort-masking ship-blocker is pinned by obligation label). Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit that referenced this pull request Jun 20, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Seq/Array misuse and
  bounds checks stay in ValidateSubscriptUsage; resolution emits no new
  diagnostics.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 20, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Seq/Array misuse and
  bounds checks stay in ValidateSubscriptUsage; resolution emits no new
  diagnostics.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 20, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected). The Seq-vs-Array
  mutability rules and bounds checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected). The Seq-vs-Array
  mutability rules and bounds checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 21, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest, and AbstractToConcreteTreeTranslatorTest
(AST→concrete→AST round-trips for the new generic emit productions; writing them surfaced
and fixed a formatter bug where the `prec(80)` `appliedType`/`newTypeArgs` ops were
parenthesized into non-re-parseable text — `(Box<int>)`, `new Box(<int>)` — corrected via
`:0` annotations on the `typeAnnotation`/`new` references), and
Core/Tests/PolyProcFreshenTest (Core-layer regression tests for CallElim per-call-site
type-var freshening — multi-instantiation verifies, the soundness twin fails at the exact
obligation, and the abort-masking ship-blocker is pinned by obligation label). Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit that referenced this pull request Jun 21, 2026
…iagnostics

Adds Seq<T> and Array<T> types with subscript read/write, a SubscriptElim
lowering pass, and a ValidateSubscriptUsage diagnostics pass.

Rebased onto reviewed-kbd-will-merge-to-main, which had advanced past the
branch point with the bidirectional type checker (#1121), Java-style ++/--
(#1320), instance-procedure lowering (#1328/#1381), old()/heap rework
(#1203/#1349), and diagnostics plumbing. Squashed into one commit. The
feature was originally written against the pre-#1121 single-pass resolver, so
bringing it up to date was more than a textual merge:

- Resolution: the old single-pass `resolveStmtExpr` no longer exists. Subscript
  typing is re-expressed in the Synth/Check architecture as `Synth.subscript`
  (a value: read synthesizes the element type, functional update synthesizes
  the sequence type) and `Check.subscriptWrite` (a statement: TVoid), each with
  the lexicographic `(exprMd, n)` termination metric. Both check the index
  against `TInt` and the written/update value against the collection's element
  type (e.g. `a[0] := true` on an `Array<int>` is rejected), and reject a
  concrete non-collection target (`5[0]` -> "expected a sequence or array")
  while letting gradual `Unknown`/unresolved targets flow, mirroring
  `Fresh`/`ReferenceEquals`. The Seq-vs-Array mutability rules and bounds
  checks stay in ValidateSubscriptUsage.
- Synth.staticCall: extended the existing polymorphic-primitive escape hatch
  (select/update/const) to the Sequence.*/Array.* ops, which carry placeholder
  `int` signatures the strict checker would otherwise reject. Result types are
  inferred structurally (e.g. `Sequence.build(s, v) : Seq<typeof v>`, so
  `[1, 2, 3] : Seq<int>`; `Sequence.empty() : Unknown`).
- LaurelAST: `Array<T>` is a surface type whose lowered forms differ — `$Array`
  after SubscriptElim, `Composite` after TypeHierarchy — while its declaration
  type is never rewritten. Added a narrow carve-out so the surface and lowered
  forms interoperate: `isConsistent` treats `Array<T>` as consistent with
  `$Array`/`Composite` (covers the `$obj != a` modifies-clause guard), and
  `isArrayInitCompatible` admits the element-checked `Seq<U> -> Array<T>`
  initialization (`var a: Array<int> := [1, 2, 3]`).
- LaurelCompilationPipeline: ported the inline SubscriptElim pass to the
  named-`def` LaurelPass architecture (`subscriptElimPass`); added
  `validateSubscriptUsage` after the initial `resolve` (it imports Resolution,
  so it can't fold into `resolve` like the diamond validator). When a program
  already failed subscript validation, a post-pass re-resolution failure is
  expected fallout, not a compiler bug, so the StrataBug guard drops it instead
  of mislabeling it.
- Exhaustiveness: the new Subscript/SubscriptWrite constructors and base's
  IncrDecr both needed arms in every wildcard-free StmtExpr walker
  (`StmtExpr.constrName`, `mapStmtExprPrePostM`, `SubscriptElim.elimExpr`,
  `ValidateSubscriptUsage.validateStmtExpr`). Dropped the stale `.THeap`/
  `.TTypedField` arms the new HighType no longer has.
- Docs: added a Subscript section and Seq/Array typing rules to LaurelDoc.
fabiomadge added a commit to fabiomadge/Strata that referenced this pull request Jun 22, 2026
…s, and datatypes

Adds user-level polymorphism to Laurel, verified end-to-end through Core/SMT. Two
mechanisms, forced by the "SMT wall" (every composite erases to one Core type):
generic COMPOSITES monomorphize; generic DATATYPES map to native Core parametric
datatypes (no monomorphization). Value-level `T` polymorphism rides Core HM freshening.

Layers (each builds green on the prior):
1. Differential-verification harness — verifyToMetrics / corpus runner / cross-solution
   diff, plus the Core.verifyWithStats split (surfaces previously-discarded statistics).
2. Type-variable substrate — HighType.TVar, Procedure/CompositeType.typeArgs,
   ResolvedNode.typeVar, resolution scoping, translateType → .ftvar.
3. Polymorphic functions — Core HM instantiation; reference args via the uniform Composite.
4. Generic composites (monomorphization) — MonomorphizeComposites: per-instantiation
   emission across every type position, with a depth cap + fuel guard that fail LOUD.
5. Polymorphic procedures — CallElim per-call-site type-var freshening; the
   procedure↔composite monomorphization fixpoint; uncalled-poly-proc witness verification.
6. `new C<τ>` explicit-type-argument syntax — grammar → AST → resolution → monomorphize.
7. Gradual-checker .TVar arms (atop strata-org#1121) — polymorphic programs type-check and translate;
   soundness guarded both directions.
8. Generic composite methods — lifted to polymorphic procedures, reusing layer 5.
9. Generic composite inheritance — concrete parent and generic parent (`Box<T> extends
   Base<T>`), with remap-aware field inheritance and topological monomorph emission.
10. Remap-aware generic upcasting — substitutedAncestors; `C<args> <: P<remapped-args>`.
11. Generic-composite field-type concretization — reject-only; closes a field-write
    wildcard wrong-accept without touching the load-bearing .TVar consistency arm.
12. Generic datatypes — native Core parametric datatypes, including the heap-stored
    composite-field box wrapper; instantiations stay distinct sorts (cross-instantiation
    rejected). Recursive and nested generics round-trip.

Invariant (verified by execution throughout): everything unsupported fails LOUD —
translated=false with a diagnostic, or a thrown type error. No silent unsoundness.

Reviewed pre-merge by a comprehensive adversarial whole-diff pass: 0 soundness findings,
0 wrong-accepts; the fail-loud invariant holds at every cross-feature seam. Tests:
PolymorphismCorpusTest (the table-driven feature corpus — poly procedures, generic
composites/methods/inheritance/upcast/field-tvar, generic datatypes), VerifyMetricsHarness
(shared Case/checkCase machinery), VerifyMetricsCorpusTest (harness self-tests + monomorphic
baseline), VerifyMetricsTest, MatchTypeArgTest, and AbstractToConcreteTreeTranslatorTest
(AST→concrete→AST round-trips for the new generic emit productions; writing them surfaced
and fixed a formatter bug where the `prec(80)` `appliedType`/`newTypeArgs` ops were
parenthesized into non-re-parseable text — `(Box<int>)`, `new Box(<int>)` — corrected via
`:0` annotations on the `typeAnnotation`/`new` references), and
Core/Tests/PolyProcFreshenTest (Core-layer regression tests for CallElim per-call-site
type-var freshening — multi-instantiation verifies, the soundness twin fails at the exact
obligation, and the abort-masking ship-blocker is pinned by obligation label). Integrates strata-org#1381
(LiftInstanceProcedure ordering) — its T9_ValueReturningInstanceMethods test passes under
the merged pass order (our lift sits at pipeline position 0, satisfying strata-org#1381's
lift-before-eliminateValueInReturns requirement). Full build green; corpus green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add type checking to Laurel

6 participants