Skip to content

Commit ca3aff5

Browse files
committed
Fix issue with infinite loops with type errors on recursive types.
Fixes #6863
1 parent 22f30e1 commit ca3aff5

File tree

3 files changed

+62
-13
lines changed

3 files changed

+62
-13
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/recursive_type.res:35:11-14
4+
5+
33 │ /* parse atom */
6+
34 │ and atom = (k, t) => {
7+
35 │ let _ = atom(k)
8+
36 │ assert(false)
9+
37 │ }
10+
11+
This uncurried function has type
12+
((option<'a>, ([> #List(list<'b>)] as 'b)) => 'c, 'd) => 'c
13+
It is applied with 1 arguments but it requires 2.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
@@uncurried
2+
3+
// test.res
4+
type rec tt = [
5+
| #List(list<tt>)
6+
]
7+
type sexp = tt
8+
9+
/* {2 Serialization (encoding)} */
10+
11+
12+
let rec expr_starting_with = (c, k, t) =>
13+
switch c {
14+
| '(' => expr_list(list{}, k, t)
15+
| c => atom(k, t)
16+
}
17+
18+
/* parse list */
19+
and expr_list = (acc, k, t) => {
20+
switch assert(false) {
21+
| ')' => k(None, #List(acc))
22+
| c =>
23+
expr_starting_with(
24+
c,
25+
(last, e) =>
26+
switch last {
27+
| _ => expr_list(list{e, ...acc}, k, t)
28+
},
29+
t,
30+
)
31+
}
32+
}
33+
/* parse atom */
34+
and atom = (k, t) => {
35+
let _ = atom(k)
36+
assert(false)
37+
}

jscomp/ml/typecore.ml

+12-13
Original file line numberDiff line numberDiff line change
@@ -3757,7 +3757,13 @@ let spellcheck_idents ppf unbound valid_idents =
37573757
spellcheck ppf (Ident.name unbound) (List.map Ident.name valid_idents)
37583758
37593759
open Format
3760-
open Printtyp
3760+
let longident = Printtyp.longident
3761+
let super_report_unification_error = Printtyp.super_report_unification_error
3762+
let report_ambiguous_type_error = Printtyp.report_ambiguous_type_error
3763+
let report_subtyping_error = Printtyp.report_subtyping_error
3764+
let type_expr ppf typ = (* print a type and avoid infinite loops *)
3765+
Printtyp.reset_and_mark_loops typ;
3766+
Printtyp.type_expr ppf typ
37613767
37623768
let report_error env ppf = function
37633769
| Polymorphic_label lid ->
@@ -3826,7 +3832,6 @@ let report_error env ppf = function
38263832
fprintf ppf "@]"
38273833
| Apply_non_function typ ->
38283834
(* modified *)
3829-
reset_and_mark_loops typ;
38303835
begin match (repr typ).desc with
38313836
Tarrow (_, _inputType, return_type, _) ->
38323837
let rec count_number_of_args count {Types.desc} = match desc with
@@ -3850,7 +3855,6 @@ let report_error env ppf = function
38503855
| l ->
38513856
fprintf ppf "with label %s" (prefixed_label_name l)
38523857
in
3853-
reset_and_mark_loops ty;
38543858
fprintf ppf
38553859
"@[<v>@[<2>The function applied to this argument has type@ %a@]@.\
38563860
This argument cannot be applied %a@]"
@@ -3867,7 +3871,6 @@ let report_error env ppf = function
38673871
fprintf ppf "The record field %a is not mutable" longident lid
38683872
| Wrong_name (eorp, ty, kind, p, name, valid_names) ->
38693873
(* modified *)
3870-
reset_and_mark_loops ty;
38713874
if Path.is_constructor_typath p then begin
38723875
fprintf ppf "@[The field %s is not part of the record \
38733876
argument for the %a constructor@]"
@@ -3899,7 +3902,6 @@ let report_error env ppf = function
38993902
fprintf ppf "but a %s was expected belonging to the %s type"
39003903
name kind)
39013904
| Undefined_method (ty, me, valid_methods) ->
3902-
reset_and_mark_loops ty;
39033905
fprintf ppf
39043906
"@[<v>@[This expression has type@;<1 2>%a@]@,\
39053907
It has no field %s@]" type_expr ty me;
@@ -3911,7 +3913,6 @@ let report_error env ppf = function
39113913
report_subtyping_error ppf env tr1 "is not a subtype of" tr2
39123914
| Too_many_arguments (in_function, ty) ->
39133915
(* modified *)
3914-
reset_and_mark_loops ty;
39153916
if in_function then begin
39163917
fprintf ppf "@[This function expects too many arguments,@ ";
39173918
fprintf ppf "it should have type@ %a@]"
@@ -3930,11 +3931,9 @@ let report_error env ppf = function
39303931
| Nolabel -> "but its first argument is not labelled"
39313932
| l -> sprintf "but its first argument is labelled %s"
39323933
(prefixed_label_name l) in
3933-
reset_and_mark_loops ty;
39343934
fprintf ppf "@[<v>@[<2>This function should have type@ %a@]@,%s@]"
39353935
type_expr ty (label_mark l)
39363936
| Scoping_let_module(id, ty) ->
3937-
reset_and_mark_loops ty;
39383937
fprintf ppf
39393938
"This `let module' expression has type@ %a@ " type_expr ty;
39403939
fprintf ppf
@@ -3976,7 +3975,7 @@ let report_error env ppf = function
39763975
"Unexpected existential"
39773976
| Unqualified_gadt_pattern (tpath, name) ->
39783977
fprintf ppf "@[The GADT constructor %s of type %a@ %s.@]"
3979-
name path tpath
3978+
name Printtyp.path tpath
39803979
"must be qualified in this pattern"
39813980
| Invalid_interval ->
39823981
fprintf ppf "@[Only character intervals are supported in patterns.@]"
@@ -4027,20 +4026,20 @@ let report_error env ppf = function
40274026
fprintf ppf "Empty record literal {} should be type annotated or used in a record context."
40284027
| Uncurried_arity_mismatch (typ, arity, args) ->
40294028
fprintf ppf "@[<v>@[<2>This uncurried function has type@ %a@]"
4030-
type_expr typ;
4029+
type_expr typ;
40314030
fprintf ppf "@ @[It is applied with @{<error>%d@} argument%s but it requires @{<info>%d@}.@]@]"
40324031
args (if args = 0 then "" else "s") arity
40334032
| Field_not_optional (name, typ) ->
40344033
fprintf ppf
4035-
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
4036-
type_expr typ
4034+
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
4035+
type_expr typ
40374036
40384037
40394038
let super_report_error_no_wrap_printing_env = report_error
40404039
40414040
40424041
let report_error env ppf err =
4043-
wrap_printing_env env (fun () -> report_error env ppf err)
4042+
Printtyp.wrap_printing_env env (fun () -> report_error env ppf err)
40444043
40454044
let () =
40464045
Location.register_error_of_exn

0 commit comments

Comments
 (0)