Skip to content

Commit ee99bff

Browse files
authored
Adjust delayed layout checks in typedecl to fix a kind inference bug. (#2246)
1 parent a932c2a commit ee99bff

File tree

9 files changed

+137
-23
lines changed

9 files changed

+137
-23
lines changed

ocaml/boot/ocamlc

840 Bytes
Binary file not shown.

ocaml/testsuite/tests/typing-layouts-float64/basics.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ Error: Layout mismatch in final type declaration consistency check.
290290
of the definition of t_float64_id at line 2, characters 0-37.
291291
But the layout of 'a must overlap with value, because
292292
it instantiates an unannotated type parameter of t5_11, defaulted to layout value.
293-
The fix will likely be to add a layout annotation on a parameter to
293+
A good next step is to add a layout annotation on a parameter to
294294
the declaration where this error is reported.
295295
|}];;
296296

ocaml/testsuite/tests/typing-layouts/annots.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,7 @@ Error: Layout mismatch in final type declaration consistency check.
358358
of the annotation on the universal variable 'a.
359359
But the layout of 'a must be a sublayout of immediate, because
360360
of the definition of t_imm at line 1, characters 0-27.
361-
The fix will likely be to add a layout annotation on a parameter to
361+
A good next step is to add a layout annotation on a parameter to
362362
the declaration where this error is reported.
363363
|}]
364364
(* CR layouts v1.5: the location on that message is wrong. But it's hard

ocaml/testsuite/tests/typing-layouts/basics.ml

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ Line 3, characters 2-27:
10261026
Error:
10271027
The layout of 'a s is float64, because
10281028
of the annotation on 'a in the declaration of the type s.
1029-
But the layout of 'a s must overlap with value, because
1029+
But the layout of 'a s must be a sublayout of value, because
10301030
it's the type of an object field.
10311031
|}];;
10321032

@@ -1838,7 +1838,7 @@ Error: Layout mismatch in final type declaration consistency check.
18381838
of the annotation on the universal variable 'a.
18391839
But the layout of 'a must be a sublayout of immediate, because
18401840
of the definition of t2_imm at line 1, characters 0-28.
1841-
The fix will likely be to add a layout annotation on a parameter to
1841+
A good next step is to add a layout annotation on a parameter to
18421842
the declaration where this error is reported.
18431843
|}]
18441844

@@ -2330,3 +2330,72 @@ Error: This expression has type t_float64
23302330
But the layout of t_float64 must be a sublayout of value, because
23312331
of the definition of t40 at line 1, characters 0-16.
23322332
|}]
2333+
2334+
(**********************************************************************)
2335+
(* Test 41: constraints in manifests in mutually recursive typedecls. *)
2336+
2337+
(* This example must be rejected. *)
2338+
type t1 = string t2 as (_ : immediate)
2339+
and 'a t2 = 'a
2340+
2341+
[%%expect{|
2342+
Line 2, characters 0-14:
2343+
2 | and 'a t2 = 'a
2344+
^^^^^^^^^^^^^^
2345+
Error: Layout mismatch in checking consistency of mutually recursive groups.
2346+
This is most often caused by the fact that type inference is not
2347+
clever enough to propagate layouts through variables in different
2348+
declarations. It is also not clever enough to produce a good error
2349+
message, so we'll say this instead:
2350+
The layout of 'a t2 is value, because
2351+
it instantiates an unannotated type parameter of t2, defaulted to layout value.
2352+
But the layout of 'a t2 must be a sublayout of immediate, because
2353+
of the annotation on the wildcard _ at line 1, characters 28-37.
2354+
A good next step is to add a layout annotation on a parameter to
2355+
the declaration where this error is reported.
2356+
|}]
2357+
2358+
(* This example is unfortunately rejected as a consequence of the fix for the
2359+
above in typedecl. If we ever change that so that the below starts working,
2360+
make sure [t1]'s parameter is immediate! Previously this was allowed and t1's
2361+
parameter was just value (a bug). *)
2362+
type 'a t1 = 'a t2 as (_ : immediate)
2363+
and 'a t2 = 'a
2364+
2365+
[%%expect{|
2366+
Line 2, characters 0-14:
2367+
2 | and 'a t2 = 'a
2368+
^^^^^^^^^^^^^^
2369+
Error: Layout mismatch in checking consistency of mutually recursive groups.
2370+
This is most often caused by the fact that type inference is not
2371+
clever enough to propagate layouts through variables in different
2372+
declarations. It is also not clever enough to produce a good error
2373+
message, so we'll say this instead:
2374+
The layout of 'a t2/2 is value, because
2375+
it instantiates an unannotated type parameter of t2, defaulted to layout value.
2376+
But the layout of 'a t2/2 must be a sublayout of immediate, because
2377+
of the annotation on the wildcard _ at line 1, characters 27-36.
2378+
A good next step is to add a layout annotation on a parameter to
2379+
the declaration where this error is reported.
2380+
|}]
2381+
2382+
(* This one also unfortunately rejected for the same reason. *)
2383+
type t1 = int t2 as (_ : immediate)
2384+
and 'a t2 = 'a
2385+
2386+
[%%expect{|
2387+
Line 2, characters 0-14:
2388+
2 | and 'a t2 = 'a
2389+
^^^^^^^^^^^^^^
2390+
Error: Layout mismatch in checking consistency of mutually recursive groups.
2391+
This is most often caused by the fact that type inference is not
2392+
clever enough to propagate layouts through variables in different
2393+
declarations. It is also not clever enough to produce a good error
2394+
message, so we'll say this instead:
2395+
The layout of 'a t2/3 is value, because
2396+
it instantiates an unannotated type parameter of t2, defaulted to layout value.
2397+
But the layout of 'a t2/3 must be a sublayout of immediate, because
2398+
of the annotation on the wildcard _ at line 1, characters 25-34.
2399+
A good next step is to add a layout annotation on a parameter to
2400+
the declaration where this error is reported.
2401+
|}]

ocaml/testsuite/tests/typing-layouts/basics_alpha.ml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,7 @@ Line 3, characters 2-24:
864864
Error:
865865
The layout of 'a s is void, because
866866
of the annotation on 'a in the declaration of the type s.
867-
But the layout of 'a s must overlap with value, because
867+
But the layout of 'a s must be a sublayout of value, because
868868
it's the type of an object field.
869869
|}];;
870870

@@ -1892,3 +1892,8 @@ Error: This expression has type t_any but an expression was expected of type
18921892
(* Test 40: unannotated type parameter defaults to layout value *)
18931893

18941894
(* Doesn't need layouts_alpha. *)
1895+
1896+
(**********************************************************************)
1897+
(* Test 41: constraints in manifests in mutually recursive typedecls. *)
1898+
1899+
(* Doesn't need layouts_alpha. *)

ocaml/testsuite/tests/typing-layouts/datatypes.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ Error: Layout mismatch in final type declaration consistency check.
392392
of the definition of float64_t at line 2, characters 0-29.
393393
But the layout of 'a must overlap with value, because
394394
it instantiates an unannotated type parameter of t8_5, defaulted to layout value.
395-
The fix will likely be to add a layout annotation on a parameter to
395+
A good next step is to add a layout annotation on a parameter to
396396
the declaration where this error is reported.
397397
|}]
398398

ocaml/testsuite/tests/typing-layouts/datatypes_alpha.ml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ Error: Layout mismatch in final type declaration consistency check.
388388
of the definition of void_t at line 1, characters 0-23.
389389
But the layout of 'a must overlap with value, because
390390
it instantiates an unannotated type parameter of t8_5, defaulted to layout value.
391-
The fix will likely be to add a layout annotation on a parameter to
391+
A good next step is to add a layout annotation on a parameter to
392392
the declaration where this error is reported.
393393
|}]
394394

@@ -410,7 +410,7 @@ Error: Layout mismatch in final type declaration consistency check.
410410
it instantiates an unannotated type parameter of t10, defaulted to layout value.
411411
But the layout of 'a must be a sublayout of immediate, because
412412
of the definition of imm_t at line 1, characters 0-27.
413-
The fix will likely be to add a layout annotation on a parameter to
413+
A good next step is to add a layout annotation on a parameter to
414414
the declaration where this error is reported.
415415
|}]
416416

@@ -430,7 +430,7 @@ Error: Layout mismatch in final type declaration consistency check.
430430
it is the primitive float64 type float#.
431431
But the layout of float# must be a sublayout of void, because
432432
of the annotation on the universal variable 'b.
433-
The fix will likely be to add a layout annotation on a parameter to
433+
A good next step is to add a layout annotation on a parameter to
434434
the declaration where this error is reported.
435435
|}]
436436

ocaml/typing/typedecl.ml

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ and reaching_type_step =
3737
| Expands_to of type_expr * type_expr
3838
| Contains of type_expr * type_expr
3939

40+
type bad_jkind_inference_location =
41+
| Check_constraints
42+
| Delayed_checks
43+
4044
type error =
4145
Repeated_parameter
4246
| Duplicate_constructor of string
@@ -73,7 +77,8 @@ type error =
7377
| Deep_unbox_or_untag_attribute of native_repr_kind
7478
| Jkind_mismatch_of_type of type_expr * Jkind.Violation.t
7579
| Jkind_mismatch_of_path of Path.t * Jkind.Violation.t
76-
| Jkind_mismatch_in_check_constraints of type_expr * Jkind.Violation.t
80+
| Jkind_mismatch_due_to_bad_inference of
81+
type_expr * Jkind.Violation.t * bad_jkind_inference_location
7782
| Jkind_sort of
7883
{ kloc : jkind_sort_loc
7984
; typ : type_expr
@@ -853,9 +858,12 @@ let rec check_constraints_rec env loc visited ty =
853858
| Unification_failure err ->
854859
raise (Error(loc, Constraint_failed (env, err)))
855860
| Jkind_mismatch { original_jkind; inferred_jkind; ty } ->
856-
raise (Error(loc, Jkind_mismatch_in_check_constraints (ty,
857-
(Jkind.Violation.of_ (Not_a_subjkind
858-
(original_jkind, inferred_jkind))))))
861+
let violation =
862+
Jkind.Violation.of_
863+
(Not_a_subjkind (original_jkind, inferred_jkind))
864+
in
865+
raise (Error(loc, Jkind_mismatch_due_to_bad_inference
866+
(ty, violation, Check_constraints)))
859867
| All_good -> ()
860868
end;
861869
List.iter (check_constraints_rec env loc visited) args
@@ -1757,11 +1765,29 @@ let transl_type_decl env rec_flag sdecl_list =
17571765
jkind checks *)
17581766
List.iter (fun (checks,loc) ->
17591767
List.iter (fun (ty,jkind) ->
1760-
match Ctype.constrain_type_jkind new_env ty jkind with
1768+
(* The use [check_type_jkind] rather than [constrain_type_jkind] here is
1769+
conservative. It ensures that the delayed checks don't succeed by
1770+
mutating type variables from the [temp_env] in a way that won't be
1771+
reflected in the final type decls and may be incompatible with them.
1772+
An alternative would be to beef up [check_constraints] and really make
1773+
sure we re-check any kind constraint that could arise from translating
1774+
the typedecl RHSs, for example by looking at Typedtree instead of
1775+
what's just in the type environment. See Test 41 in
1776+
[tests/typing-layouts/basics.ml] for a subtle example. *)
1777+
match Ctype.check_type_jkind new_env ty jkind with
17611778
| Ok _ -> ()
17621779
| Error err ->
1763-
let err = Errortrace.unification_error ~trace:[Bad_jkind (ty,err)] in
1764-
raise (Error (loc, Type_clash (new_env, err))))
1780+
(* This inner match is just here to detect when we're rejecting this
1781+
program because we're being conservative in the sense of the previous
1782+
comment, and issue an error admitting to it. *)
1783+
begin match Ctype.constrain_type_jkind new_env ty jkind with
1784+
| Error _ ->
1785+
let err = Errortrace.unification_error ~trace:[Bad_jkind (ty,err)] in
1786+
raise (Error (loc, Type_clash (new_env, err)))
1787+
| Ok _ ->
1788+
raise (Error (loc, Jkind_mismatch_due_to_bad_inference
1789+
(ty, err, Delayed_checks)))
1790+
end)
17651791
checks)
17661792
delayed_jkind_checks;
17671793
(* Check that all type variables are closed; this also defaults any remaining
@@ -2662,15 +2688,23 @@ module Reaching_path = struct
26622688
pp path
26632689
end
26642690

2665-
let report_jkind_mismatch_in_check_constraints ppf ty violation =
2691+
let report_jkind_mismatch_due_to_bad_inference ppf ty violation loc =
2692+
let loc =
2693+
match loc with
2694+
| Check_constraints ->
2695+
"final type declaration consistency check"
2696+
| Delayed_checks ->
2697+
"checking consistency of mutually recursive groups"
2698+
in
26662699
fprintf ppf
2667-
"@[<v>Layout mismatch in final type declaration consistency check.@ \
2700+
"@[<v>Layout mismatch in %s.@ \
26682701
This is most often caused by the fact that type inference is not@ \
26692702
clever enough to propagate layouts through variables in different@ \
26702703
declarations. It is also not clever enough to produce a good error@ \
26712704
message, so we'll say this instead:@;<1 2>@[%a@]@ \
2672-
The fix will likely be to add a layout annotation on a parameter to@ \
2705+
A good next step is to add a layout annotation on a parameter to@ \
26732706
the declaration where this error is reported.@]"
2707+
loc
26742708
(Jkind.Violation.report_with_offender
26752709
~offender:(fun ppf -> Printtyp.type_expr ppf ty)) violation
26762710

@@ -2722,16 +2756,17 @@ let report_error ppf = function
27222756
in
27232757
begin match List.find_map get_jkind_error err.trace with
27242758
| Some (ty, violation) ->
2725-
report_jkind_mismatch_in_check_constraints ppf ty violation
2759+
report_jkind_mismatch_due_to_bad_inference ppf ty violation
2760+
Check_constraints
27262761
| None ->
27272762
fprintf ppf "@[<v>Constraints are not satisfied in this type.@ ";
27282763
Printtyp.report_unification_error ppf env err
27292764
(fun ppf -> fprintf ppf "Type")
27302765
(fun ppf -> fprintf ppf "should be an instance of");
27312766
fprintf ppf "@]"
27322767
end
2733-
| Jkind_mismatch_in_check_constraints (ty, violation) ->
2734-
report_jkind_mismatch_in_check_constraints ppf ty violation
2768+
| Jkind_mismatch_due_to_bad_inference (ty, violation, loc) ->
2769+
report_jkind_mismatch_due_to_bad_inference ppf ty violation loc
27352770
| Non_regular { definition; used_as; defined_as; reaching_path } ->
27362771
let reaching_path = Reaching_path.simplify reaching_path in
27372772
Printtyp.prepare_for_printing [used_as; defined_as];

ocaml/typing/typedecl.mli

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ and reaching_type_step =
7878
| Expands_to of type_expr * type_expr
7979
| Contains of type_expr * type_expr
8080

81+
type bad_jkind_inference_location =
82+
| Check_constraints
83+
| Delayed_checks
84+
8185
type error =
8286
Repeated_parameter
8387
| Duplicate_constructor of string
@@ -114,7 +118,8 @@ type error =
114118
| Deep_unbox_or_untag_attribute of native_repr_kind
115119
| Jkind_mismatch_of_type of type_expr * Jkind.Violation.t
116120
| Jkind_mismatch_of_path of Path.t * Jkind.Violation.t
117-
| Jkind_mismatch_in_check_constraints of type_expr * Jkind.Violation.t
121+
| Jkind_mismatch_due_to_bad_inference of
122+
type_expr * Jkind.Violation.t * bad_jkind_inference_location
118123
| Jkind_sort of
119124
{ kloc : jkind_sort_loc
120125
; typ : type_expr

0 commit comments

Comments
 (0)