Skip to content

Commit 61bd1ea

Browse files
cristianoccknitt
authored andcommitted
Fix issue with infinite loops with type errors on recursive types.
Fixes rescript-lang#6863
1 parent eb3485d commit 61bd1ea

File tree

4 files changed

+63
-13
lines changed

4 files changed

+63
-13
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
- Fix tag function location on compiler error. https://github.com/rescript-lang/rescript-compiler/pull/6816
1818
- Fix Deno compatibility issues on Windows. https://github.com/rescript-lang/rescript-compiler/pull/6850
19+
- Fix issue with infinite loops with type errors on recursive types. https://github.com/rescript-lang/rescript-compiler/pull/6867
1920

2021
# 11.1.3-rc.1
2122

Lines changed: 13 additions & 0 deletions
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.
Lines changed: 37 additions & 0 deletions
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

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3798,7 +3798,13 @@ let spellcheck_idents ppf unbound valid_idents =
37983798
spellcheck ppf (Ident.name unbound) (List.map Ident.name valid_idents)
37993799
38003800
open Format
3801-
open Printtyp
3801+
let longident = Printtyp.longident
3802+
let super_report_unification_error = Printtyp.super_report_unification_error
3803+
let report_ambiguous_type_error = Printtyp.report_ambiguous_type_error
3804+
let report_subtyping_error = Printtyp.report_subtyping_error
3805+
let type_expr ppf typ = (* print a type and avoid infinite loops *)
3806+
Printtyp.reset_and_mark_loops typ;
3807+
Printtyp.type_expr ppf typ
38023808
38033809
let report_error env ppf = function
38043810
| Polymorphic_label lid ->
@@ -3867,7 +3873,6 @@ let report_error env ppf = function
38673873
fprintf ppf "@]"
38683874
| Apply_non_function typ ->
38693875
(* modified *)
3870-
reset_and_mark_loops typ;
38713876
begin match (repr typ).desc with
38723877
Tarrow (_, _inputType, returnType, _) ->
38733878
let rec countNumberOfArgs count {Types.desc} = match desc with
@@ -3891,7 +3896,6 @@ let report_error env ppf = function
38913896
| l ->
38923897
fprintf ppf "with label %s" (prefixed_label_name l)
38933898
in
3894-
reset_and_mark_loops ty;
38953899
fprintf ppf
38963900
"@[<v>@[<2>The function applied to this argument has type@ %a@]@.\
38973901
This argument cannot be applied %a@]"
@@ -3908,7 +3912,6 @@ let report_error env ppf = function
39083912
fprintf ppf "The record field %a is not mutable" longident lid
39093913
| Wrong_name (eorp, ty, kind, p, name, valid_names) ->
39103914
(* modified *)
3911-
reset_and_mark_loops ty;
39123915
if Path.is_constructor_typath p then begin
39133916
fprintf ppf "@[The field %s is not part of the record \
39143917
argument for the %a constructor@]"
@@ -3940,7 +3943,6 @@ let report_error env ppf = function
39403943
fprintf ppf "but a %s was expected belonging to the %s type"
39413944
name kind)
39423945
| Undefined_method (ty, me, valid_methods) ->
3943-
reset_and_mark_loops ty;
39443946
fprintf ppf
39453947
"@[<v>@[This expression has type@;<1 2>%a@]@,\
39463948
It has no field %s@]" type_expr ty me;
@@ -3966,7 +3968,6 @@ let report_error env ppf = function
39663968
"Consider using a double coercion."
39673969
| Too_many_arguments (in_function, ty) ->
39683970
(* modified *)
3969-
reset_and_mark_loops ty;
39703971
if in_function then begin
39713972
fprintf ppf "@[This function expects too many arguments,@ ";
39723973
fprintf ppf "it should have type@ %a@]"
@@ -3985,11 +3986,9 @@ let report_error env ppf = function
39853986
| Nolabel -> "but its first argument is not labelled"
39863987
| l -> sprintf "but its first argument is labelled %s"
39873988
(prefixed_label_name l) in
3988-
reset_and_mark_loops ty;
39893989
fprintf ppf "@[<v>@[<2>This function should have type@ %a@]@,%s@]"
39903990
type_expr ty (label_mark l)
39913991
| Scoping_let_module(id, ty) ->
3992-
reset_and_mark_loops ty;
39933992
fprintf ppf
39943993
"This `let module' expression has type@ %a@ " type_expr ty;
39953994
fprintf ppf
@@ -4031,7 +4030,7 @@ let report_error env ppf = function
40314030
"Unexpected existential"
40324031
| Unqualified_gadt_pattern (tpath, name) ->
40334032
fprintf ppf "@[The GADT constructor %s of type %a@ %s.@]"
4034-
name path tpath
4033+
name Printtyp.path tpath
40354034
"must be qualified in this pattern"
40364035
| Invalid_interval ->
40374036
fprintf ppf "@[Only character intervals are supported in patterns.@]"
@@ -4082,20 +4081,20 @@ let report_error env ppf = function
40824081
fprintf ppf "Empty record literal {} should be type annotated or used in a record context."
40834082
| Uncurried_arity_mismatch (typ, arity, args) ->
40844083
fprintf ppf "@[<v>@[<2>This uncurried function has type@ %a@]"
4085-
type_expr typ;
4084+
type_expr typ;
40864085
fprintf ppf "@ @[It is applied with @{<error>%d@} argument%s but it requires @{<info>%d@}.@]@]"
40874086
args (if args = 0 then "" else "s") arity
40884087
| Field_not_optional (name, typ) ->
40894088
fprintf ppf
4090-
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
4091-
type_expr typ
4089+
"Field @{<info>%s@} is not optional in type %a. Use without ?" name
4090+
type_expr typ
40924091
40934092
40944093
let super_report_error_no_wrap_printing_env = report_error
40954094
40964095
40974096
let report_error env ppf err =
4098-
wrap_printing_env env (fun () -> report_error env ppf err)
4097+
Printtyp.wrap_printing_env env (fun () -> report_error env ppf err)
40994098
41004099
let () =
41014100
Location.register_error_of_exn

0 commit comments

Comments
 (0)