Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- Rewatch: preserve warnings after atomic-save full rebuilds. https://github.com/rescript-lang/rescript/pull/8358

- Preserve JSX prop locations across the AST0 translation layer, fixing `0:0` editor diagnostics in PPX-related flows. https://github.com/rescript-lang/rescript/pull/8350
- Fix type lowering for `dict{}` and `async`, so you don't need to annotate one extra time when the type is known. https://github.com/rescript-lang/rescript/pull/8359

#### :memo: Documentation

Expand Down
24 changes: 24 additions & 0 deletions compiler/ml/typecore.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2259,6 +2259,19 @@ let extract_function_name funct =
| Texp_ident (path, _, _) -> Some (Longident.parse (Path.name path))
| _ -> None

let should_unify_expected_result_before_typing_lowered_apply funct sargs =
match (extract_function_name funct, sargs) with
| ( Some (Longident.Ldot (Longident.Lident "Primitive_dict", "make")),
[(Asttypes.Nolabel, {Parsetree.pexp_desc = Parsetree.Pexp_array _})] ) ->
(* Dict literals *)
true
| ( Some
(Longident.Ldot (Longident.Lident "Primitive_promise", "unsafe_async")),
[(Asttypes.Nolabel, _)] ) ->
(* Async wrapper *)
true
| _ -> false

type lazy_args =
(Asttypes.arg_label * (unit -> Typedtree.expression) option) list

Expand Down Expand Up @@ -2460,6 +2473,17 @@ and type_expect_ ?deprecated_context ~context ?in_function ?(recarg = Rejected)
let funct =
type_exp ~deprecated_context:FunctionCall ~context:None env sfunct
in
(if should_unify_expected_result_before_typing_lowered_apply funct sargs
then
(* Lowered syntax like dict literals and async wrappers becomes a regular
application, so thread the expected result type into the application
before typing its arguments. *)
let _, ty_res =
filter_arrow ~env
~arity:(Some (List.length sargs))
funct.exp_type Nolabel
in
unify_exp_types ~context:None loc env ty_res (instance env ty_expected));
let ty = instance env funct.exp_type in
end_def ();
wrap_trace_gadt_instances env (lower_args env []) ty;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@

We've found a bug for you!
/.../fixtures/dict_show_no_coercion.res:2:23-35
/.../fixtures/dict_show_no_coercion.res:2:33-34

1 │ // This should not show coercion suggestion since just the inner types a
│ re coercable, not the full type + expression (dict<float> -> dict<JSON.t
│ >)
2 │ let x: dict<JSON.t> = dict{"1": 1.}
2 │ let x: dict<JSON.t> = dict{"1": 1.}
3 │

This has type: dict<float>
But it's expected to have type: dict<JSON.t>

The incompatible parts:
float vs JSON.t (defined as JSON.t)
This has type: float
But it's expected to have type: JSON.t (defined as JSON.t)
30 changes: 30 additions & 0 deletions tests/tests/src/DictScopedRecordLiteral.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Generated by ReScript, PLEASE EDIT WITH CARE


let Hidden = {};

let dictValueInference = {
health: {
get: 200
}
};

async function asyncValueInference() {
return {
get: 200
};
}

let primitiveMakeValueInference = {
health: {
get: 200
}
};

export {
Hidden,
dictValueInference,
asyncValueInference,
primitiveMakeValueInference,
}
/* No side effect */
13 changes: 13 additions & 0 deletions tests/tests/src/DictScopedRecordLiteral.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Hidden = {
type routeHandlerObject = {get: int}
}

let dictValueInference: Dict.t<Hidden.routeHandlerObject> = dict{
"health": {get: 200},
}

let asyncValueInference: unit => promise<Hidden.routeHandlerObject> = async () => {
get: 200,
}

let primitiveMakeValueInference: Dict.t<Hidden.routeHandlerObject> = dict{"health": {get: 200}}
Loading