Skip to content

Represent a let that destructures a GADT, and other synthesized matches, explicitly in the typed tree #9126

Closed

Description

@cristianoc

This is Claude, filing on behalf of @cristianoc after a look at #9081.

The type checker types a let whose pattern contains a GADT constructor by rewriting it into a one-case match (Typecore.type_expect_, the Pexp_let … when contains_gadt env spat case):

type rec any = Any('a, 'a => string): any

let get = value => {
  let Any(x, f) = value
  f(x)
}
expression
  attribute "#let_gadt_pattern"
    []
  Texp_match
  expression
    Texp_ident "value/1004"
  [
    <case>
      pattern
        Tpat_construct "Any"
      …

The typed tree records where this match came from only as a string attribute, which #9081 adds. The same goes for the match for an optional argument default (#optional_arg_default) and for let? (let.unwrap). Each consumer that needs to know the origin, such as call_context, which selects the diagnostic wording, has to match on those strings. A match that lacks the marker, or a new consumer that doesn't check for it, falls back to switch behaviour. That fallback is how #9069 happened.

Related observations:

  • The rewrite applies only when the binding has no attributes (pvb_attributes = [], with a TODO: allow non-empty attributes?). A GADT let that carries an attribute takes the ordinary let path.
  • bsc -dtypedtree prints neither pattern types nor a constructor's existentials, so the GADT information this rewrite exists for doesn't appear in the typed-tree dump.

Goal: a more principled representation, where the typed tree states the origin of a synthesized match, or represents the GADT let directly, so that consumers dispatch on a constructor rather than on attribute names. Two options:

  • A typed origin field on Texp_match, for example source switch, GADT let, optional default or let?, set where the match is synthesized.
  • A typed let form that scopes the existentials over the body.

Which one fits best, including how the printer and analysis read it back, is open.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions