diff --git a/CHANGELOG.md b/CHANGELOG.md index ed95148fd7..0c51e3b4f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ #### :bug: Bug fix +- Avoid crash when using locally abstract types in `type … .` annotations with ticked params; emit a proper diagnostic. https://github.com/rescript-lang/rescript/pull/7851 + #### :memo: Documentation #### :nail_care: Polish diff --git a/compiler/syntax/src/res_core.ml b/compiler/syntax/src/res_core.ml index 805874b161..5f599165f1 100644 --- a/compiler/syntax/src/res_core.ml +++ b/compiler/syntax/src/res_core.ml @@ -2623,7 +2623,25 @@ and parse_let_binding_body ~start_pos ~attrs p = Parser.expect Equal p; let expr = parse_expr p in let loc = mk_loc start_pos p.prev_end_pos in - let exp, poly = wrap_type_annotation ~loc newtypes typ expr in + (* varify_constructors may raise Syntaxerr.Error when a locally + abstract type variable is referenced as a ticked Ptyp_var inside + the annotation (e.g., event<'t>). + Catch it and surface a friendly diagnostic instead of crashing. *) + let exp, poly = + try wrap_type_annotation ~loc newtypes typ expr with + | Syntaxerr.Error (Syntaxerr.Variable_in_scope (loc', v)) -> + let hint = + "Locally abstract type `" ^ v + ^ "` is already in scope here. Inside `type ... .` annotations,\n" + ^ "refer to these type parameters without a leading quote, e.g.\n" + ^ "`event` instead of `event<'inputStream, 'callback>`." + in + Parser.err ~start_pos:loc'.loc_start ~end_pos:loc'.loc_end p + (Diagnostics.message hint); + (* Fall back to a simple poly type to keep parsing going. *) + let poly = Ast_helper.Typ.poly ~loc newtypes typ in + (expr, poly) + in let pat = Ast_helper.Pat.constraint_ ~loc pat poly in (pat, exp) | _ -> diff --git a/tests/build_tests/super_errors/expected/locally_abstract_type_ticked_params.res.expected b/tests/build_tests/super_errors/expected/locally_abstract_type_ticked_params.res.expected new file mode 100644 index 0000000000..a0c7dad1a1 --- /dev/null +++ b/tests/build_tests/super_errors/expected/locally_abstract_type_ticked_params.res.expected @@ -0,0 +1,12 @@ + + Syntax error! + /.../fixtures/locally_abstract_type_ticked_params.res:11:55-56 + + 9 │ | End + 10 │ + 11 │ let rec patternMatching : type inputStream callback. (ev: event<'inputS + │ tream, 'callback>) => unit { + 12 │ switch ev { + 13 │ | Pipe => patternMatching(Data) + + A labeled parameter starts with a `~`. Did you mean: `~ev`? \ No newline at end of file diff --git a/tests/build_tests/super_errors/fixtures/locally_abstract_type_ticked_params.res b/tests/build_tests/super_errors/fixtures/locally_abstract_type_ticked_params.res new file mode 100644 index 0000000000..1254a2fea7 --- /dev/null +++ b/tests/build_tests/super_errors/fixtures/locally_abstract_type_ticked_params.res @@ -0,0 +1,18 @@ +// Repro for rescript-lang/rescript#7850 +// Using locally abstract types with ticked params inside the annotation +// previously threw an uncaught Syntaxerr.Error. This fixture ensures we +// surface a proper diagnostic instead. + +type event<'inputStream,'callback> = + | Pipe + | Data + | End + +let rec patternMatching : type inputStream callback. (ev: event<'inputStream, 'callback>) => unit { + switch ev { + | Pipe => patternMatching(Data) + | Data => patternMatching(End) + | End => () + } +} +