-
Notifications
You must be signed in to change notification settings - Fork 469
Fix super error mishandling uncurried function #6694
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
|
||
[1;31mWe've found a bug for you![0m | ||
[36m/.../fixtures/UncurriedArgsNotApplied.res[0m:[2m3:15-21[0m | ||
|
||
1 [2m│[0m let apply = (fn: (. unit) => option<int>) => fn(. ()) | ||
2 [2m│[0m | ||
[1;31m3[0m [2m│[0m let _ = apply([1;31mSome(1)[0m) | ||
4 [2m│[0m | ||
|
||
This value might need to be [1;33mwrapped in a function that takes an extra | ||
parameter[0m of type unit | ||
|
||
[1;33mHere's the original error message[0m | ||
This has type: [1;31moption<'a>[0m | ||
But it's expected to have type: [1;33m(. unit) => option<int>[0m | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
let apply = (fn: (. unit) => option<int>) => fn(. ()) | ||
|
||
let _ = apply(Some(1)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -69,14 +69,20 @@ let coreTypeIsUncurriedFun (typ : Parsetree.core_type) = | |
true | ||
| _ -> false | ||
|
||
let typeIsUncurriedFun = Ast_uncurried_utils.typeIsUncurriedFun | ||
|
||
let typeExtractUncurriedFun (typ : Parsetree.core_type) = | ||
let coreTypeExtractUncurriedFun (typ : Parsetree.core_type) = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed from typeExtractUncurriedFun coreTypeExtractUncurriedFun to follow naming convention in this file. I I have redefined typeExtractUncurriedFun below. (coreTypeIsUncurriedFun is named above fore the same paramater type, and for functions with Types.type_expr as a param use typeIsUncurredFun and typeExtractUncurriedFun respectively) |
||
match typ.ptyp_desc with | ||
| Ptyp_constr ({txt = Lident "function$"}, [tArg; tArity]) -> | ||
(arityFromType tArity, tArg) | ||
| _ -> assert false | ||
|
||
let typeIsUncurriedFun = Ast_uncurried_utils.typeIsUncurriedFun | ||
|
||
let typeExtractUncurriedFun (typ : Types.type_expr) = | ||
match typ.desc with | ||
| Tconstr (Pident {name = "function$"}, [tArg; _], _) -> | ||
tArg | ||
| _ -> assert false | ||
|
||
(* Typed AST *) | ||
|
||
let arity_to_type arity = | ||
|
@@ -114,3 +120,6 @@ let uncurried_type_get_arity_opt ~env typ = | |
| Tconstr (Pident { name = "function$" }, [ _t; tArity ], _) -> | ||
Some (type_to_arity tArity) | ||
| _ -> None | ||
|
||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -204,7 +204,8 @@ let typeClashContextMaybeOption ty_expected ty_res = | |
| ( {Types.desc = Tconstr (expectedPath, _, _)}, | ||
{Types.desc = Tconstr (typePath, _, _)} ) | ||
when Path.same Predef.path_option typePath | ||
&& Path.same expectedPath Predef.path_option = false -> | ||
&& Path.same expectedPath Predef.path_option = false | ||
&& Path.same expectedPath Predef.path_uncurried = false -> | ||
Comment on lines
+207
to
+208
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here was another gremlin I came across where you get a suggestion to unwrap your option. For the example in the tests/descriptioon you get:
Where the possible solution is not meant to be for functions but uncurried functions still pattern match on this case. |
||
Some MaybeUnwrapOption | ||
| _ -> None | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -307,7 +307,9 @@ let extract_concrete_record env ty = | |
|
||
let extract_concrete_variant env ty = | ||
match extract_concrete_typedecl env ty with | ||
(p0, p, {type_kind=Type_variant cstrs}) -> (p0, p, cstrs) | ||
(p0, p, {type_kind=Type_variant cstrs}) | ||
when not (Ast_uncurried.typeIsUncurriedFun ty) | ||
-> (p0, p, cstrs) | ||
Comment on lines
+310
to
+312
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was the first issue, leading to the initial bad super error being displayed. The uncurried function type would extract as a concrete variant since it matched this case when it should not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm sure you've read and know more about this, but instead of throwing an exception with Not_found if uncurried, what about an implementation that extracts the uncurried case? Something like this. if Ast_uncurried_utils.typeIsUncurriedFun ty then
extract_concrete_variant env (Ast_uncurried.typeExtractUncurriedFun ty)
else (p0, p, cstrs) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hey @mununki thanks for the comment! Yes I think that feel a lot nicer except that in practice it would make no difference to this function since if it is an uncurried function the extracted type would not be Type_variant? So happy to add the refactor to make it more future proof but otherwise it should never hit a case where it is an uncurried function and it can extract a concrete variant There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for my misunderstanding, if so why do we need that when clause by then? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It's because an uncurried function is represented by this pattern Tconstr (Pident {name = "function$"}, [tArg; _], _) where tArg is the underlying type of So when trying to extract the concrete type as a variant, it matches the case of Tconstr, but is not actually variant it's essentially just a wrapper around the underlying function. So we get a false positive. |
||
| (p0, p, {type_kind=Type_open}) -> (p0, p, []) | ||
| _ -> raise Not_found | ||
|
||
|
@@ -662,6 +664,9 @@ let rec collect_missing_arguments env type1 type2 = match type1 with | |
| Some res -> Some ((label, argtype) :: res) | ||
| None -> None | ||
end | ||
| t when Ast_uncurried.typeIsUncurriedFun t -> | ||
let typ = Ast_uncurried.typeExtractUncurriedFun t in | ||
collect_missing_arguments env typ type2 | ||
| _ -> None | ||
|
||
let print_expr_type_clash ?typeClashContext env trace ppf = begin | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This now matches the super error that was outputted when a curried function was defined