Semantic Diff

#9128 Pass the origin of a synthesized match as an argument, not an attribute

1 commit

6ea63e5a9114711e68d92f0eb4b355848a8fd337..pr-9128

338681144 · cknitt + Claude · Oct 29, 2026, 18:08 UTC

Pass the origin of a synthesized match as an argument, not an attribute

Why

The type checker rewrites a let destructuring a GADT constructor, and an optional parameter's default, into a match, and marked that match with the string attributes #let_gadt_pattern and #optional_arg_default so that it gets function-style diagnostics rather than a switch's (#9126). Both are made and read inside typecore and nothing after typing reads them. type_expect now takes ?match_context and type_let takes ?optional_default; only let.unwrap, which comes from the parsed let?, stays an attribute. The GADT rewrite also required the binding to have no attributes, so a doc comment or @warning in front of it was an error; its attributes now go on the case pattern, and @warning on a pattern now covers that pattern's unused variables.

modifiedTypedtree let destructuring a GADT constructor

type rec any = Any('a, 'a => string): any let get = value => {  let Any(x, f) = value  f(x)}
typed
Before
After
expressionexpression├─ attribute "#let_gadt_pattern"│  └─ [] ├─ Texp_match├─ Texp_match└─ expression└─ expression   ├─ Texp_ident "value/1004"   ├─ Texp_ident "value/1004"   └─ <case>   └─ <case>      ├─ pattern      ├─ pattern      │  └─ Tpat_construct "Any"      │  └─ Tpat_construct "Any"      └─ …      └─ …

removedDiagnostic attribute in front of a GADT let

type rec any = Any('a, 'a => string): any let get = value => {  /** Destructures the existential. */  let Any(x, f) = value  f(x)}
diagnostic
Before
After
This pattern introduces an existential type from a GADT constructor,which is not allowed here. Match on it inside a switch instead.compiles

removedDiagnostic unused variable of a pattern with @warning

let silenced = o =>  switch o {  | @warning("-27") Some(x) => 1  | None => 0  }
diagnostic
Before
After
Warning number 27unused variable x.no warning

Fixes: #9126

Review

  • Why not a typed origin field on Texp_match, as #9126 suggests? Nothing after typing reads the origin; the field would change the typed tree for no consumer.
  • Does @warning("-8") on a GADT let cover a non-exhaustive pattern? No: the exhaustiveness check runs for the whole match, outside the case pattern's warning scope, as for a switch case.