diff --git a/.agents/skills/records/SKILL.md b/.agents/skills/records/SKILL.md index cebb83d86d..7a405b0887 100644 --- a/.agents/skills/records/SKILL.md +++ b/.agents/skills/records/SKILL.md @@ -177,10 +177,32 @@ The table lists the common kinds. ## What a commit holds Every commit says why it is made. A commit that changes what the compiler -or a tool does gets one object block for each object it changes, with the -smallest example that shows the change. A refactor, a test, a script or a -review fix needs no block, only its subject and a line or two of prose; a -review fix names the finding it answers. +or a tool does shows each representation, rule, transformation or decision +it changes, Before and After, at the level where it operates, then the +representative consequences that show why it matters: the blocks go from +the changed operation to what it affects, and one block serves both when +the operation directly changes the output shown. Each change the prose +names, such as an attribute the compiler adds or a case a decision takes, +is also shown in a block. Each block has the smallest example that shows +its change. + +- A printed form shows the change when one exposes it. Otherwise a block + shows a schematic, captioned with the function that implements it: an + inference rule for a changed typing judgment, a clause matrix and its + split for the match compiler, a mapping from inputs to results for a + decision, keeping the premises, priorities and side conditions that + matter. +- Printing each form for the example before and after the commit finds + the layers it changes; the record keeps the excerpts that show the + changed operation and its distinct consequences. +- When an error stops later forms from being printed, the internal forms + come from a related example that compiles, the diagnostic from one that + fails, and the prose says how they relate. + +A commit whose changes are only organization, tests or documentation +needs no block, only its subject and a line or two of prose; a script or +a review fix that changes behaviour gets blocks like any other. A review +fix names the finding it answers. ## Rendering diff --git a/changes/existential-let-context.polish.md b/changes/existential-let-context.polish.md new file mode 100644 index 0000000000..cd1a0c853c --- /dev/null +++ b/changes/existential-let-context.polish.md @@ -0,0 +1 @@ +- A type error in the body after a `let` that destructures a GADT constructor no longer talks about switch branches. diff --git a/compiler/ml/typecore.ml b/compiler/ml/typecore.ml index a2b5fdbb8f..da87c06dc8 100644 --- a/compiler/ml/typecore.ml +++ b/compiler/ml/typecore.ml @@ -2644,6 +2644,8 @@ and type_expect_ ?deprecated_context ~context ?(recarg = Rejected) env sexp { sexp with pexp_desc = Pexp_match (sval, [Ast_helper.Exp.case spat sbody]); + pexp_attributes = + (mknoloc "#let_gadt_pattern", PStr []) :: sexp.pexp_attributes; } ty_expected | Pexp_let (rec_flag, spat_sexp_list, sbody) -> @@ -2832,10 +2834,13 @@ and type_expect_ ?deprecated_context ~context ?(recarg = Rejected) env sexp in let call_context = (* Optional-default lowering synthesizes a match expression, but from the - user's point of view this is still part of a function definition. Use - function-style diagnostics instead of reporting a phantom switch. *) + user's point of view this is still part of a function definition. A + [let] destructuring a GADT constructor is typed as a one-case match, + whose body is the rest of the block. Use function-style diagnostics + for both instead of reporting a phantom switch. *) if has_attr "let.unwrap" then `LetUnwrap - else if has_attr "#optional_arg_default" then `Function + else if has_attr "#optional_arg_default" || has_attr "#let_gadt_pattern" + then `Function else `Switch in let val_cases, partial = diff --git a/tests/build_tests/super_errors/expected/gadt_existential_let.res.expected b/tests/build_tests/super_errors/expected/gadt_existential_let.res.expected new file mode 100644 index 0000000000..47d788e64a --- /dev/null +++ b/tests/build_tests/super_errors/expected/gadt_existential_let.res.expected @@ -0,0 +1,14 @@ + + We've found a bug for you! + /.../fixtures/gadt_existential_let.res:5:3 + + 3 │ let get = value => { + 4 │ let Any(x, _) = value + 5 │ x + 6 │ } + 7 │ + + This has type: $a + But it's expected to have type: 'a + $a is an existential type bound by the constructor Any. + It is only known in the scope of the pattern that matches Any. \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/gadt_existential_let.res b/tests/build_tests/super_errors/fixtures/gadt_existential_let.res new file mode 100644 index 0000000000..f1b2221ee7 --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/gadt_existential_let.res @@ -0,0 +1,6 @@ +type rec any = Any('a, 'a => string): any + +let get = value => { + let Any(x, _) = value + x +}