Skip to content

Commit 27a6e0a

Browse files
committed
error message for when passing polyvariant where variant is expected
1 parent a76bba6 commit 27a6e0a

5 files changed

+97
-0
lines changed

compiler/ml/error_message_utils.ml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,17 @@ let is_record_type ~extract_concrete_typedecl ~env ty =
195195
| _ -> false
196196
with _ -> false
197197
198+
let is_variant_and_has_constructor ~env ~extract_concrete_typedecl
199+
~constructor_name ty =
200+
try
201+
match extract_concrete_typedecl env ty with
202+
| _, _, {Types.type_kind = Type_variant constructors; _} ->
203+
List.exists
204+
(fun {Types.cd_id = {name = cname; _}; _} -> cname = constructor_name)
205+
constructors
206+
| _ -> false
207+
with _ -> false
208+
198209
let print_extra_type_clash_help ~extract_concrete_typedecl ~env loc ppf
199210
(bottom_aliases : (Types.type_expr * Types.type_expr) option)
200211
type_clash_context =
@@ -354,6 +365,43 @@ let print_extra_type_clash_help ~extract_concrete_typedecl ~env loc ppf
354365
| _, Some ({Types.desc = Tconstr (p1, _, _)}, _)
355366
when Path.same p1 Predef.path_promise ->
356367
fprintf ppf "\n\n - Did you mean to await this promise before using it?\n"
368+
| ( _,
369+
Some
370+
( {
371+
Types.desc =
372+
Tvariant
373+
{row_fields = [(constructor_name, _)]; row_closed = false};
374+
},
375+
ty ) )
376+
when is_variant_and_has_constructor ~env ~extract_concrete_typedecl
377+
~constructor_name ty ->
378+
(* This does not take into account whether the constructor actually
379+
takes a payload, but it should be good enough. *)
380+
let suggested_rewrite =
381+
Parser.reprint_expr_at_loc loc ~mapper:(fun exp ->
382+
match exp.Parsetree.pexp_desc with
383+
| Pexp_variant (constructor_name, payload) ->
384+
Some
385+
{
386+
exp with
387+
Parsetree.pexp_desc =
388+
Pexp_construct
389+
( Location.mknoloc (Longident.Lident constructor_name),
390+
payload );
391+
}
392+
| _ -> None)
393+
in
394+
fprintf ppf
395+
"\n\n\
396+
\ The type expected is a variant (not polymorphic variant). The \
397+
expected variant has a constructor named @{<info>%s@}, did you mean to \
398+
use that?\n\n\
399+
Possible solutions:\n\
400+
\ - Change the code to use the variant constructor, like: @{<info>%s@}\n"
401+
constructor_name
402+
(match suggested_rewrite with
403+
| Some rewrite -> rewrite
404+
| None -> constructor_name)
357405
| _, Some ({Types.desc = Tconstr (p1, _, _)}, {Types.desc = Ttuple _})
358406
when Path.same p1 Predef.path_array ->
359407
let suggested_rewrite =
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/passing_polyvariant_where_variant_is_expected.res:7:12-15
4+
5+
5 │ }
6+
6 │
7+
7 │ let _ = do(#One)
8+
8 │
9+
10+
This has type: [> #One]
11+
But this function argument is expecting: variant
12+
13+
The type expected is a variant (not polymorphic variant). The expected variant has a constructor named One, did you mean to use that?
14+
15+
Possible solutions:
16+
- Change the code to use the variant constructor, like: One
17+

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
We've found a bug for you!
3+
/.../fixtures/passing_polyvariant_with_payload_where_variant_is_expected.res:8:12-23
4+
5+
6 │ }
6+
7 │
7+
8 │ let _ = do(#One("test"))
8+
9 │
9+
10+
This has type: [> #One(string)]
11+
But this function argument is expecting: variant
12+
13+
The type expected is a variant (not polymorphic variant). The expected variant has a constructor named One, did you mean to use that?
14+
15+
Possible solutions:
16+
- Change the code to use the variant constructor, like: One("test")
17+

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type variant = One | Two
2+
3+
let do = (x: variant) => {
4+
(x :> string)
5+
}
6+
7+
let _ = do(#One)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@unboxed
2+
type variant = One(string) | Two
3+
4+
let do = (x: variant) => {
5+
(x :> string)
6+
}
7+
8+
let _ = do(#One("test"))

0 commit comments

Comments
 (0)