Skip to content

Commit

Permalink
[Normalizer] Fix type alias expansion in type_app
Browse files Browse the repository at this point in the history
Summary:
When normalizing:
```
TypeAppT (t, ts)
```
where
*  `t` is a type alias `T`, s.t. `type T<vs> = body`
* the mode is to expand type aliases

we need to replace `vs` for `ts` in `body`. This diffs makes this substitution.

This didn't occur until now, because we weren't expanding type aliases, even when the
relevant flag required up to.

Reviewed By: samwgoldman

Differential Revision: D8528866

fbshipit-source-id: 562216071e3e520b67501e00c6a097a967f4d6a1
  • Loading branch information
panagosg7 authored and facebook-github-bot committed Jun 23, 2018
1 parent 7923fbb commit 40a72f8
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 2 deletions.
62 changes: 60 additions & 2 deletions src/typing/ty_normalizer.ml
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,56 @@ end = struct

end


module Substitution = struct
module Env = struct
type t = Ty.t SMap.t
let descend _ e = e
end
module Visitor = Ty_visitor.MakeAny(Env)

(* Replace a list of type parameters with a list of types in the given type.
* These lists might not match exactly in length.
*)
let run =
let open Ty in
let init_env tparams types =
let rec step acc = function
| [], _ | _, [] -> acc
| p::ps, t::ts -> step (SMap.add p.tp_name t acc) (ps, ts)
in
step SMap.empty (tparams, types)
in
let remove_params env = function
| None -> env
| Some ps -> List.fold_left (fun e p -> SMap.remove p.tp_name e) env ps
in
let open Visitor in
let visitor = object inherit c as super
method! type_ env t =
match t with
| TypeAlias { ta_tparams=ps; _ }
| Fun { fun_type_params=ps; _ } ->
let env = remove_params env ps in
super#type_ env t
| Bound (Symbol (_, name)) ->
begin match SMap.get name env with
| Some t' ->
(* Mark the substitution *)
begin tell true >>= fun _ ->
super#type_ env t' end
| _ -> super#type_ env t
end
| _ -> super#type_ env t
end
in
fun vs ts t_body ->
let env = init_env vs ts in
let t, changed = visitor#type_ env t_body in
if changed then simplify_unions_inters t else t

end

(***********************)
(* Construct built-ins *)
(***********************)
Expand Down Expand Up @@ -1076,9 +1126,17 @@ end = struct
type__ ~env t >>= fun ty ->
mapM (type__ ~env) targs >>= fun targs ->
match ty with
| Ty.Class (name, _, _)
| Ty.TypeAlias { Ty.ta_name=name; _ } ->
| Ty.Class (name, _, _) ->
return (Ty.generic_t name targs)
| Ty.TypeAlias { Ty.ta_name; ta_tparams; ta_type } ->
let t = if C.opt_expand_type_aliases then
match ta_tparams, ta_type with
| Some ps, Some t -> Substitution.run ps targs t
| None, Some t -> t
| _ -> Ty.generic_t ta_name targs
else
Ty.generic_t ta_name targs
in return t
| Ty.Any ->
return Ty.Any
(* "Fix" type application on recursive types *)
Expand Down
11 changes: 11 additions & 0 deletions tests/type-at-pos/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,14 @@ printf "type-alias.js:19:8 "
assert_ok "$FLOW" type-at-pos type-alias.js 19 8 --strip-root --pretty
printf "type-alias.js:20:8 "
assert_ok "$FLOW" type-at-pos type-alias.js 20 8 --strip-root --pretty

printf "type-alias.js:24:6 "
assert_ok "$FLOW" type-at-pos type-alias.js 24 6 --strip-root --pretty --expand-type-aliases
printf "type-alias.js:25:6 "
assert_ok "$FLOW" type-at-pos type-alias.js 25 6 --strip-root --pretty --expand-type-aliases
printf "type-alias.js:27:6 "
assert_ok "$FLOW" type-at-pos type-alias.js 27 6 --strip-root --pretty --expand-type-aliases
printf "type-alias.js:29:6 "
assert_ok "$FLOW" type-at-pos type-alias.js 29 6 --strip-root --pretty --expand-type-aliases
printf "type-alias.js:31:6 "
assert_ok "$FLOW" type-at-pos type-alias.js 31 6 --strip-root --pretty --expand-type-aliases
10 changes: 10 additions & 0 deletions tests/type-at-pos/type-alias.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,13 @@ function f<X>() {
type E = $Exact<X>;
type F = ?X;
}

type G<X> = X | null;
type H = G<number>;
type I = G<G<number> | string>
type J<X> = (<X>(x: X) => void) | X | null;
type K = J<number>;
type L<X, Y> = (<X>(x: X, y: Y) => void) | X | Y | null;
type M<Z> = L<number, Z>;
type N<A> = { x: N<A> } | null;
type O = N<number>
75 changes: 75 additions & 0 deletions tests/type-at-pos/type-at-pos.exp
Original file line number Diff line number Diff line change
Expand Up @@ -3573,3 +3573,78 @@ type-alias.js:20:8 {
"start":8,
"end":8
}
type-alias.js:24:6 {
"type":"type H = number | null",
"reasons":[],
"loc":{
"source":"type-alias.js",
"type":"SourceFile",
"start":{"line":24,"column":6,"offset":364},
"end":{"line":24,"column":6,"offset":365}
},
"path":"type-alias.js",
"line":24,
"endline":24,
"start":6,
"end":6
}
type-alias.js:25:6 {
"type":"type I = string | number | null",
"reasons":[],
"loc":{
"source":"type-alias.js",
"type":"SourceFile",
"start":{"line":25,"column":6,"offset":384},
"end":{"line":25,"column":6,"offset":385}
},
"path":"type-alias.js",
"line":25,
"endline":25,
"start":6,
"end":6
}
type-alias.js:27:6 {
"type":"type K = (<X>(x: X) => void) | number | null",
"reasons":[],
"loc":{
"source":"type-alias.js",
"type":"SourceFile",
"start":{"line":27,"column":6,"offset":459},
"end":{"line":27,"column":6,"offset":460}
},
"path":"type-alias.js",
"line":27,
"endline":27,
"start":6,
"end":6
}
type-alias.js:29:6 {
"type":"type M<Z> = (<X>(x: X, y: Z) => void) | number | Z | null",
"reasons":[],
"loc":{
"source":"type-alias.js",
"type":"SourceFile",
"start":{"line":29,"column":6,"offset":536},
"end":{"line":29,"column":6,"offset":537}
},
"path":"type-alias.js",
"line":29,
"endline":29,
"start":6,
"end":6
}
type-alias.js:31:6 {
"type":"type O = {x: ({x: N<number>} | null)} | null",
"reasons":[],
"loc":{
"source":"type-alias.js",
"type":"SourceFile",
"start":{"line":31,"column":6,"offset":594},
"end":{"line":31,"column":6,"offset":595}
},
"path":"type-alias.js",
"line":31,
"endline":31,
"start":6,
"end":6
}

0 comments on commit 40a72f8

Please sign in to comment.