solved some TODOs about Tgeneric type arguments (2)
[hiphop-php.git] / hphp / hack / src / typing / typing_dependent_type.ml
blob099e0b2b99d104ff274c00e6af7f8688bad51f47
1 (*
2 * Copyright (c) 2015, Facebook, Inc.
3 * All rights reserved.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
8 *)
10 open Hh_prelude
11 open Typing_defs
13 module ExprDepTy = struct
14 module N = Aast
15 module Env = Typing_env
16 module TUtils = Typing_utils
18 let new_ () =
19 let eid = Ident.tmp () in
20 (Reason.ERexpr eid, DTexpr eid)
22 let from_cid env reason cid =
23 let pos = Reason.to_pos reason in
24 let (pos, expr_dep_reason, dep) =
25 match cid with
26 | N.CIparent ->
27 (match Env.get_parent_id env with
28 | Some cls -> (pos, Reason.ERparent cls, DTcls cls)
29 | None ->
30 let (ereason, dep) = new_ () in
31 (pos, ereason, dep))
32 | N.CIself ->
33 (match get_node (Env.get_self env) with
34 | Tclass ((_, cls), _, _) -> (pos, Reason.ERself cls, DTcls cls)
35 | _ ->
36 let (ereason, dep) = new_ () in
37 (pos, ereason, dep))
38 | N.CI (p, cls) -> (p, Reason.ERclass cls, DTcls cls)
39 | N.CIstatic -> (pos, Reason.ERstatic, DTthis)
40 | N.CIexpr (p, N.This) -> (p, Reason.ERstatic, DTthis)
41 (* If it is a local variable then we look up the expression id associated
42 * with it. If one doesn't exist we generate a new one. We are being
43 * conservative here because the new expression id we create isn't
44 * added to the local enviornment.
46 | N.CIexpr (p, N.Lvar (_, x)) ->
47 let (ereason, dep) =
48 match Env.get_local_expr_id env x with
49 | Some eid -> (Reason.ERexpr eid, DTexpr eid)
50 | None -> new_ ()
52 (p, ereason, dep)
53 (* If all else fails we generate a new identifier for our expression
54 * dependent type.
56 | N.CIexpr (p, _) ->
57 let (ereason, dep) = new_ () in
58 (p, ereason, dep)
60 (Reason.Rexpr_dep_type (reason, pos, expr_dep_reason), dep)
62 (****************************************************************************)
63 (* A type access "this::T" is translated to "<this>::T" during the
64 * naming phase. While typing a body, "<this>" is a type hole that needs to
65 * be filled with a final concrete type. Resolution is specified in typing.ml,
66 * here is a high level break down:
68 * 1) When a class member "bar" is accessed via "[CID]->bar" or "[CID]::bar"
69 * we resolve "<this>" in the type of "bar" to "<[CID]>"
71 * 2) When typing a method, we resolve "<this>" in the return type to
72 * "this"
74 * 3) When typing a method, we resolve "<this>" in parameters of the
75 * function to "<static>" in static methods or "<$this>" in non-static
76 * methods
78 * More specific details are explained inline
80 (****************************************************************************)
81 let make env ~cid ty =
82 let (r_dep_ty, dep_ty) = from_cid env (get_reason ty) cid in
83 let apply env ty = (env, mk (r_dep_ty, Tdependent (dep_ty, ty))) in
84 let rec make env ty =
85 let (env, ety) = Env.expand_type env ty in
86 match deref ety with
87 | (_, Tclass (_, Exact, _)) -> (env, ty)
88 | (_, Tclass (((_, x) as c), Nonexact, tyl)) ->
89 let class_ = Env.get_class env x in
90 (* If a class is both final and variant, we must treat it as non-final
91 * since we can't statically guarantee what the runtime type
92 * will be.
95 Option.value_map class_ ~default:false ~f:(fun class_ty ->
96 TUtils.class_is_final_and_not_contravariant class_ty)
97 then
98 (env, ty)
99 else (
100 match dep_ty with
101 | DTcls n when String.equal n x ->
102 (env, mk (r_dep_ty, Tclass (c, Exact, tyl)))
103 | _ -> apply env ty
105 | (_, Tgeneric (s, _tyargs)) when DependentKind.is_generic_dep_ty s ->
106 (* TODO(T69551141) handle type arguments *)
107 (env, ty)
108 | (_, Tgeneric _) ->
109 (* TODO(T69551141) handle type arguments here? *)
110 let (env, tyl) = Typing_utils.get_concrete_supertypes env ty in
111 let (env, tyl') = List.fold_map tyl ~init:env ~f:make in
112 if tyl_equal tyl tyl' then
113 (env, ty)
114 else
115 apply env ty
116 | (_, Tpu _) -> apply env ty
117 | (r, Toption ty) ->
118 let (env, ty) = make env ty in
119 (env, mk (r, Toption ty))
120 | (r, Tnewtype (n, p, ty)) ->
121 let (env, ty) = make env ty in
122 (env, mk (r, Tnewtype (n, p, ty)))
123 | (_, Tdependent (_, _)) -> (env, ty)
124 | (r, Tunion tyl) ->
125 let (env, tyl) = List.fold_map tyl ~init:env ~f:make in
126 (env, mk (r, Tunion tyl))
127 | (r, Tintersection tyl) ->
128 let (env, tyl) = List.fold_map tyl ~init:env ~f:make in
129 (env, mk (r, Tintersection tyl))
130 (* TODO(T36532263) check if this is legal *)
131 | ( _,
132 ( Tobject | Tnonnull | Tprim _ | Tshape _ | Ttuple _ | Tdynamic
133 | Tvarray _ | Tdarray _ | Tvarray_or_darray _ | Tfun _ | Tany _
134 | Tvar _ | Terr | Tpu_type_access _ ) ) ->
135 (env, ty)
137 make env ty