Skip to content

Commit 640749c

Browse files
Andrew Kennedyfacebook-github-bot
authored andcommitted
Force supportdyn on element type when widening for array get
Summary: For array access (e.g. `$x['a']`) through a value whose type is a type variable (e.g. `$x : #0`), we use lower bounds on the type variable (e.g. `Map<string,int> <: #0`) to "narrow" the possible solutions in order to type-check the access. Here, for example, we would use the lower bound to generate a type `KeyedContainer<#1,#2>` that, roughly speaking, is the widest type that supports the operation that is compatible with the lower bound constraint. We generate a subtype assertion between the lower bound and the "widened" type i.e. `Map<string,int> <: KeyedContainer<#1, #2>`. Note the type variables. Here, `#2` has no constraints, and so solves to `mixed`. In the case that the original type variable has an *upper bound* that supports dynamic (e.g. `supportdyn<mixed>`), this produces code that fails our "pessimisation" conjecture (see new test). Instead, we can employ a heuristic: if the lower bound does support dynamic, then assert that the widened type also supports dynamic. We also generalize the treatment of open shapes, generating a type variable for the "unknown fields" (which typically will solve to `supportdyn<mixed>`) rather than fixing it to be `mixed`. Differential Revision: D46872355 fbshipit-source-id: 5ad70f81aa92ab4278c6e68f6ea5b87c2f2b60fa
1 parent a1e1bfe commit 640749c

File tree

2 files changed

+15
-2
lines changed

2 files changed

+15
-2
lines changed

hphp/hack/src/typing/typing_array_access.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,13 +151,14 @@ let widen_for_array_get ~lhs_of_null_coalesce ~expr_pos index_expr env ty =
151151
((env, None), None)
152152
| _ ->
153153
let (env, element_ty) = Env.fresh_type_invariant env expr_pos in
154+
let (env, rest_ty) = Env.fresh_type_invariant env expr_pos in
154155
let upper_fdm =
155156
TShapeMap.add
156157
field
157158
{ sft_optional = lhs_of_null_coalesce; sft_ty = element_ty }
158159
TShapeMap.empty
159160
in
160-
let upper_shape_ty = MakeType.open_shape r upper_fdm in
161+
let upper_shape_ty = MakeType.shape r rest_ty upper_fdm in
161162
((env, None), Some upper_shape_ty))
162163
end
163164
| _ -> ((env, None), None)

hphp/hack/src/typing/typing_solver.ml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,19 @@ let expand_type_and_narrow
880880
@@ Some (Typing_error.Reasons_callback.unify_error_at p)
881881
in
882882
(match res with
883-
| (env, None) -> ((env, None), widened_ty)
883+
| (env, None) ->
884+
let supportdyn = Typing_utils.is_supportdyn env ty in
885+
let res2 =
886+
if supportdyn then begin
887+
TUtils.sub_type
888+
env
889+
widened_ty
890+
(MakeType.supportdyn_mixed (Reason.Rwitness p))
891+
@@ Some (Typing_error.Reasons_callback.unify_error_at p)
892+
end else
893+
(env, None)
894+
in
895+
(res2, widened_ty)
884896
| _ ->
885897
if force_solve then
886898
expand_type_and_solve env ~description_of_expected p ty

0 commit comments

Comments
 (0)