Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions .agents/skills/records/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 1 addition & 0 deletions changes/existential-let-context.polish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- A type error in the body after a `let` that destructures a GADT constructor no longer talks about switch branches.
11 changes: 8 additions & 3 deletions compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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) ->
Expand Down Expand Up @@ -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 =
Expand Down
Original file line number Diff line number Diff line change
@@ -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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
type rec any = Any('a, 'a => string): any

let get = value => {
let Any(x, _) = value
x
}
Loading