folly: fix github ci tests on macos arm
[hiphop-php.git] / hphp / hack / src / typing / typing_enforceable_hint.ml
blobda0ee0bfeadecbf3265241f1190325b23d1cfbc5
1 (*
2 * Copyright (c) 2018, 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
12 module Env = Typing_env
13 module Reason = Typing_reason
14 module Cls = Folded_class
15 module SN = Naming_special_names
17 let validator =
18 object (this)
19 inherit Type_validator.type_validator as super
21 (* Only comes about because naming has reported an error and left Hany *)
22 method! on_tany acc _ = acc
24 method! on_tprim acc r prim =
25 match prim with
26 | Aast.Tvoid -> this#invalid acc r "the `void` type"
27 | Aast.Tnoreturn -> this#invalid acc r "the `noreturn` type"
28 | _ -> acc
30 method! on_tfun acc r _fun_type = this#invalid acc r "a function type"
32 method! on_tvar acc r _id = this#invalid acc r "an unknown type"
34 method! on_typeconst acc class_ typeconst =
35 match typeconst.ttc_kind with
36 | TCConcrete _ -> super#on_typeconst acc class_ typeconst
37 | TCAbstract _
38 when (* get_typeconst_enforceability should always return Some here, since we
39 know the typeconst exists (else we wouldn't be in this method).
40 But since we have to map it to a bool anyway, we just use
41 Option.value_map. *)
42 Option.value_map
43 ~f:snd
44 ~default:false
45 (Cls.get_typeconst_enforceability
46 class_
47 (snd typeconst.ttc_name)) ->
48 super#on_typeconst acc class_ typeconst
49 | TCAbstract _ ->
50 let (pos, tconst) = typeconst.ttc_name in
51 let r = Reason.witness_from_decl pos in
52 this#invalid acc r
53 @@ "the abstract type constant "
54 ^ tconst
55 ^ " because it is not marked `<<__Enforceable>>`"
57 method! on_tgeneric acc r name _tyargs =
58 (* If we allow higher-kinded generics to be enforceable at some point,
59 handle type arguments here *)
60 this#check_generic acc r name
62 method! on_newtype acc r sid _ as_cstr _super_cstr _ =
63 if String.equal (snd sid) SN.Classes.cSupportDyn then
64 this#on_type acc (with_reason as_cstr r)
65 else
66 this#invalid acc r "a `newtype`"
68 method! on_tlike acc _r ty = this#on_type acc ty
70 method! on_class acc r cls tyl =
71 match Env.get_class acc.Type_validator.env (snd cls) with
72 | Decl_entry.Found tc ->
73 (match Cls.kind tc with
74 | Ast_defs.Ctrait -> this#invalid acc r "a trait name"
75 | _ ->
76 let tparams = Cls.tparams tc in
77 begin
78 match tyl with
79 | [] -> acc
80 (* this case should really be handled by the fold2,
81 but we still allow class hints without args in certain places *)
82 | targs ->
83 List.Or_unequal_lengths.(
84 begin
85 match
86 List.fold2
87 ~init:acc
88 targs
89 tparams
90 ~f:(fun acc targ tparam ->
91 let inside_reified_class_generic_position =
92 acc
93 .Type_validator
94 .inside_reified_class_generic_position
96 if this#is_wildcard targ then begin
97 if inside_reified_class_generic_position then
98 this#invalid
99 acc
101 "a reified type containing a wildcard (`_`)"
102 else
104 end else if
105 Aast.(equal_reify_kind tparam.tp_reified Reified)
106 then
107 this#on_type
109 acc with
110 Type_validator
111 .inside_reified_class_generic_position = true;
113 targ
114 else if inside_reified_class_generic_position then
115 this#on_type acc targ
116 else
117 let error_message =
118 "a type with an erased generic type argument"
120 this#invalid acc r error_message)
121 with
122 | Ok new_acc -> new_acc
123 | Unequal_lengths -> acc (* arity error elsewhere *)
124 end)
125 end)
126 | Decl_entry.DoesNotExist
127 | Decl_entry.NotYetAvailable ->
130 method! on_alias acc r _id tyl ty =
131 match List.filter ~f:(fun ty -> not @@ this#is_wildcard ty) tyl with
132 | [] -> this#on_type acc ty
133 | _ ->
134 this#invalid
137 "a type with generics, because generics are erased at runtime"
139 method! on_tunion acc r tyl =
140 match tyl with
141 | [] -> this#invalid acc r "the `nothing` type"
142 | _ -> super#on_tunion acc r tyl
144 method! on_tintersection acc r _ =
145 this#invalid
148 "an intersection type, which is restricted to coeffects"
150 method is_wildcard ty =
151 match get_node ty with
152 | Twildcard -> true
153 | _ -> false
155 method check_for_wildcards acc tyl s =
156 match List.filter tyl ~f:this#is_wildcard with
157 | [] -> acc
158 | tyl ->
159 this#invalid_list
161 (List.map tyl ~f:(fun ty ->
162 ( Typing_defs_core.get_reason ty,
163 "_ in a " ^ s ^ " (use `mixed` instead)" )))
165 method! on_ttuple acc _ tyl =
166 let acc = List.fold_left tyl ~f:this#on_type ~init:acc in
167 this#check_for_wildcards acc tyl "tuple"
169 method! on_tshape acc _ { s_fields = fdm; _ } =
170 let tyl = TShapeMap.values fdm |> List.map ~f:(fun s -> s.sft_ty) in
171 let acc = List.fold_left tyl ~init:acc ~f:this#on_type in
172 this#check_for_wildcards acc tyl "shape"
174 method check_generic acc r name =
175 (* No need to look at type arguments of generic var, as higher-kinded type params
176 cannot be enforcable *)
177 (* TODO(T70069116) implement enforcability check *)
178 match
179 ( Env.get_reified acc.Type_validator.env name,
180 Env.get_enforceable acc.Type_validator.env name )
181 with
182 | (Aast.Erased, _) ->
183 this#invalid acc r "an erased generic type parameter"
184 | (Aast.SoftReified, _) ->
185 this#invalid acc r "a soft reified generic type parameter"
186 | (Aast.Reified, false) ->
187 (* If a reified generic is an argument to a reified class it does not
188 * need to be enforceable *)
189 if acc.Type_validator.inside_reified_class_generic_position then
191 else
192 this#invalid
195 "a reified type parameter that is not marked `<<__Enforceable>>`"
196 | (Aast.Reified, true) -> acc
199 let validate_hint = validator#validate_hint ?reification:None
201 let validate_type = validator#validate_type ?reification:None