2 * Copyright (c) 2015, Facebook, Inc.
5 * This source code is licensed under the MIT license found in the
6 * LICENSE file in the "hack" directory of this source tree.
14 module Env
= Typing_env
15 module TUtils
= Typing_utils
16 module Reason
= Typing_reason
17 module Union
= Typing_union
18 module Inter
= Typing_intersection
19 module MakeType
= Typing_make_type
20 module SubType
= Typing_subtype
21 module Partial
= Partial_provider
22 module GenericRules
= Typing_generic_rules
23 open String.Replace_polymorphic_compare
25 let err_witness env p
= TUtils.terr env
(Reason.Rwitness p
)
27 let error_array env p ty
=
28 Errors.array_access_read p
(get_pos ty
) (Typing_print.error env ty
);
29 (env
, err_witness env p
)
31 let error_const_mutation env p ty
=
32 Errors.const_mutation p
(get_pos ty
) (Typing_print.error env ty
);
33 (env
, err_witness env p
)
35 let error_assign_array_append env p ty
=
36 Errors.array_append p
(get_pos ty
) (Typing_print.error env ty
);
39 (* Given a type `ty` known to be a lower bound on the type of the array operand
40 * to an array get operation, compute the largest upper bound on that type
41 * that validates the get operation. For example, if `vec<string>` is a lower
42 * bound, then the type must be a subtype of `KeyedContainer<#1,#2>` for some
43 * unresolved types #1 and #2. If `(string,int)` is a lower bound, then
44 * `(#1, #2)` is a suitable upper bound. Shapes are the most complex. If
45 * `shape(known_fields, ...)` is a lower bound (an open shape type), and the
46 * access is through a literal field f, then `shape('f' => #1, ...)` is a
47 * suitable upper bound.
49 let widen_for_array_get ~lhs_of_null_coalesce ~expr_pos index_expr env ty
=
51 log_with_level env
"typing" 1 (fun () ->
55 [Log_head
("widen_for_array_get", [Log_type
("ty", ty
)])]));
57 (* The null type is valid only with a null-coalescing use of array get *)
58 | (_
, Tprim Tnull
) when lhs_of_null_coalesce
-> (env
, Some ty
)
59 (* dynamic is valid for array get *)
60 | (_
, Tdynamic
) -> (env
, Some ty
)
61 (* All class-based containers, and keyset, vec and dict, are subtypes of
62 * some instantiation of KeyedContainer
64 | (r
, Tclass
((_
, cn
), _
, _
))
65 when cn
= SN.Collections.cVector
66 || cn
= SN.Collections.cVec
67 || cn
= SN.Collections.cMap
68 || cn
= SN.Collections.cDict
69 || cn
= SN.Collections.cKeyset
70 || cn
= SN.Collections.cConstMap
71 || cn
= SN.Collections.cImmMap
72 || cn
= SN.Collections.cKeyedContainer
73 || cn
= SN.Collections.cAnyArray
74 || cn
= SN.Collections.cConstVector
75 || cn
= SN.Collections.cImmVector
->
76 let (env
, element_ty
) = Env.fresh_invariant_type_var env expr_pos
in
77 let (env
, index_ty
) = Env.fresh_invariant_type_var env expr_pos
in
78 let ty = MakeType.keyed_container r index_ty element_ty
in
80 (* The same is true of PHP arrays *)
81 | (r
, (Tvarray _
| Tdarray _
| Tvec_or_dict _
| Tvarray_or_darray _
)) ->
82 let (env
, element_ty
) = Env.fresh_invariant_type_var env expr_pos
in
83 let (env
, index_ty
) = Env.fresh_invariant_type_var env expr_pos
in
84 let ty = MakeType.keyed_container r index_ty element_ty
in
86 (* For tuples, we just freshen the element types *)
88 (* requires integer literal *)
91 (* Should freshen type variables *)
94 List.map_env env tyl
(fun env _ty
->
95 Env.fresh_invariant_type_var env expr_pos
)
97 (env
, Some
(MakeType.tuple r params
))
100 (* Whatever the lower bound, construct an open, singleton shape type. *)
101 | (r
, Tshape
(_
, fdm
)) ->
103 match TUtils.shape_field_name env index_expr
with
104 | None
-> (env
, None
)
106 let field = TShapeField.of_ast
(fun p
-> p
) field in
107 (match TShapeMap.find_opt
field fdm
with
108 (* If field is in the lower bound but is optional, then no upper bound makes sense
109 * unless this is a null-coalesce access *)
110 | Some
{ sft_optional
= true; _
} when not lhs_of_null_coalesce
->
113 let (env
, element_ty
) = Env.fresh_invariant_type_var env expr_pos
in
117 { sft_optional
= lhs_of_null_coalesce
; sft_ty
= element_ty
}
120 let upper_shape_ty = mk
(r
, Tshape
(Open_shape
, upper_fdm)) in
121 (env
, Some
upper_shape_ty))
125 (* Check that an index to a map-like collection passes the basic test of
126 * being a subtype of arraykey
128 let check_arraykey_index error env pos container_ty index_ty
=
129 if TypecheckerOptions.disallow_invalid_arraykey
(Env.get_tcopt env
) then
130 let (env
, container_ty
) = Env.expand_type env container_ty
in
132 match get_node container_ty
with
133 | Tclass
((_
, cn
), _
, _
) -> Reason.index_class cn
134 | _
-> Reason.index_array
136 let info_of_type ty = (get_pos
ty, Typing_print.error env
ty) in
137 let ty_arraykey = MakeType.arraykey
(Reason.Ridx_dict pos
) in
138 (* Wrap generic type mismatch error with special error code *)
139 Typing_coercion.coerce_type
144 { et_type
= ty_arraykey; et_enforced
= true }
146 error pos
(info_of_type container_ty
) (info_of_type index_ty
))
150 let check_arraykey_index_read =
151 check_arraykey_index Errors.invalid_arraykey_read
153 let check_arraykey_index_write =
154 check_arraykey_index Errors.invalid_arraykey_write
159 ?
(lhs_of_null_coalesce
= false)
166 Typing_solver.expand_type_and_narrow
168 ~description_of_expected
:"an array or collection"
169 (widen_for_array_get ~lhs_of_null_coalesce ~expr_pos e2
)
174 GenericRules.apply_rules ~ignore_type_structure
:true env ty1
(fun env ty1
->
175 let (r
, ety1_
) = deref ty1
in
176 (* This is a little weird -- we enforce the right arity when you use certain
177 * collections, even in partial mode (where normally completely omitting the
178 * type parameter list is admitted). Basically the "omit type parameter"
179 * hole was for compatibility with certain interfaces like Arrayaccess, not
180 * for collections! But it's hard to go back on now, so since we've always
181 * errored (with an inscrutable error message) when you try to actually use
182 * a collection with omitted type parameters, we can continue to error and
183 * give a more useful error message. *)
184 let arity_error (_
, name
) =
185 Errors.array_get_arity expr_pos name
(Reason.to_pos r
)
187 let nullable_container_get env
ty =
190 (* Normally, we would not allow indexing into a nullable container,
191 however, because the pattern shows up so frequently, we are allowing
192 indexing into a nullable container as long as it is on the lhs of a
198 ~lhs_of_null_coalesce
205 Errors.null_container
208 "This is what makes me believe it can be `null`."
210 (env
, err_witness env expr_pos
)
213 let type_index env p ty_have ty_expect
reason =
215 log_with_level env
"typing" 1 (fun () ->
221 ( "array_get/type_index",
223 Log_type
("ty_have", ty_have
);
224 Log_type
("ty_expect", ty_expect
);
228 (* coerce if possible *)
230 Typing_coercion.try_coerce
233 { et_type
= ty_expect
; et_enforced
= true }
237 (* if subtype of dynamic, allow it to be used *)
239 Typing_solver.is_sub_type env ty_have
(MakeType.dynamic
Reason.none
)
242 (* fail with useful error *)
250 Errors.index_type_mismatch
254 let ty1 = MakeType.int (Reason.Ridx
(fst e2
, r
)) in
255 let env = type_index env expr_pos ty2
ty1 Reason.index_array
in
257 | Tclass
(((_
, cn
) as id
), _
, argl
)
258 when String.equal cn
SN.Collections.cVector
259 || String.equal cn
SN.Collections.cVec
->
265 err_witness env expr_pos
267 let ty1 = MakeType.int (Reason.Ridx_vector
(fst e2
)) in
268 let env = type_index env expr_pos ty2
ty1 (Reason.index_class cn
) in
270 | Tclass
(((_
, cn
) as id
), _
, argl
)
271 when cn
= SN.Collections.cMap
272 || cn
= SN.Collections.cDict
273 || cn
= SN.Collections.cKeyset
->
274 if cn
= SN.Collections.cKeyset
&& is_lvalue
then (
275 Errors.keyset_set expr_pos
(Reason.to_pos r
);
276 (env, err_witness env expr_pos
)
280 | [t
] when String.equal cn
SN.Collections.cKeyset
-> (t
, t
)
281 | [k
; v
] when String.( <> ) cn
SN.Collections.cKeyset
-> (k
, v
)
284 let any = err_witness env expr_pos
in
287 (* dict and keyset are covariant in the key type, so subsumption
288 * lets you upcast the key type beyond ty2 to arraykey.
289 * e.g. consider $d: dict<string,int> and $i:int
290 * and $d[$i] should actually type check because
291 * dict<string,int> <: dict<arraykey,int>
293 let (env, k
) = Env.expand_type
env k
in
296 String.equal cn
SN.Collections.cDict
297 || String.equal cn
SN.Collections.cKeyset
299 check_arraykey_index_read env expr_pos
ty1 ty2
301 type_index env expr_pos ty2 k
(Reason.index_class cn
)
304 (* Certain container/collection types are intended to be immutable/const,
305 * thus they should never appear as a lvalue when indexing i.e.
307 * $x[0] = 100; // ERROR
310 | Tclass
(((_
, cn
) as id
), _
, argl
)
311 when String.equal cn
SN.Collections.cConstMap
312 || String.equal cn
SN.Collections.cImmMap
313 || String.equal cn
SN.Collections.cKeyedContainer
314 || String.equal cn
SN.Collections.cAnyArray
->
316 error_const_mutation env expr_pos
ty1
323 let any = err_witness env expr_pos
in
326 let env = check_arraykey_index_read env expr_pos
ty1 ty2
in
328 | Tclass
(((_
, cn
) as id
), _
, argl
)
330 && ( String.equal cn
SN.Collections.cConstVector
331 || String.equal cn
SN.Collections.cImmVector
) ->
337 err_witness env expr_pos
339 let ty1 = MakeType.int (Reason.Ridx
(fst e2
, r
)) in
340 let env = type_index env expr_pos ty2
ty1 (Reason.index_class cn
) in
342 | Tclass
((_
, cn
), _
, _
)
344 && ( String.equal cn
SN.Collections.cConstVector
345 || String.equal cn
SN.Collections.cImmVector
) ->
346 error_const_mutation env expr_pos
ty1
348 | Tvec_or_dict
(_k
, v
)
349 | Tvarray_or_darray
(_k
, v
) ->
350 let env = check_arraykey_index_read env expr_pos
ty1 ty2
in
352 | Terr
-> (env, err_witness env expr_pos
)
353 | Tdynamic
-> (env, ty1)
354 | Tany _
-> (env, TUtils.mk_tany
env expr_pos
)
356 let ty = MakeType.string (Reason.Rwitness expr_pos
) in
357 let ty1 = MakeType.int (Reason.Ridx
(fst e2
, r
)) in
358 let env = type_index env expr_pos ty2
ty1 Reason.index_array
in
361 (* requires integer literal *)
364 let idx = int_of_string_opt n
in
365 (match Option.bind
idx ~f
:(List.nth tyl
) with
366 | Some nth
-> (env, nth
)
368 Errors.typing_error p
(Reason.string_of_ureason
Reason.index_tuple
);
369 (env, err_witness env p
))
371 Errors.typing_error p
(Reason.string_of_ureason
Reason.URtuple_access
);
372 (env, err_witness env p
))
373 | Tclass
(((_
, cn
) as id
), _
, argl
)
374 when String.equal cn
SN.Collections.cPair
->
377 | [ty1; ty2
] -> (ty1, ty2
)
380 let any = err_witness env expr_pos
in
383 (* requires integer literal *)
386 let idx = int_of_string_opt n
in
387 (match Option.bind ~f
:(List.nth
[ty1; ty2
]) idx with
388 | Some nth
-> (env, nth
)
390 Errors.typing_error p
391 @@ Reason.string_of_ureason
(Reason.index_class cn
);
392 (env, err_witness env p
))
394 Errors.typing_error p
(Reason.string_of_ureason
Reason.URpair_access
);
395 (env, err_witness env p
))
397 if is_lvalue
|| lhs_of_null_coalesce
then
398 (* The expression $s['x'] ?? $y is semantically equivalent to
399 Shapes::idx ($s, 'x') ?? $y. I.e., if $s['x'] occurs on
400 the left of a coalesce operator, then for type checking it
401 can be treated as if it evaluated to null instead of
402 throwing an exception if the field 'x' doesn't exist in $s.
410 ~fun_pos
:Reason.Rnone
415 match TUtils.shape_field_name
env e2
with
417 (* there was already an error in shape_field name,
418 don't report another one for a missing field *)
419 (env, err_witness env p)
421 let field = TShapeField.of_ast
(fun p -> p) field in
423 match TShapeMap.find_opt
field fdm
with
425 Errors.undefined_field
427 ~name
:(TUtils.get_printable_shape_field_name
field)
428 ~shape_type_pos
:(Reason.to_pos r
);
429 (env, err_witness env p)
430 | Some
{ sft_optional
; sft_ty
} ->
431 if sft_optional
then (
434 ~f
:(fun x
-> TShapeField.equal
field x
)
437 Errors.array_get_with_optional_field
439 (Env.get_shape_field_name_pos
declared_field)
440 (TUtils.get_printable_shape_field_name
field);
441 (env, err_witness env p)
446 | Toption
ty -> nullable_container_get env ty
448 let ty = MakeType.nothing
Reason.Rnone
in
449 nullable_container_get env ty
451 if Partial.should_check_error
(Env.get_mode
env) 4005 then
452 error_array env expr_pos
ty1
454 (env, TUtils.mk_tany
env expr_pos
)
455 | Tnewtype
(ts
, [ty], bound
) ->
457 match deref bound
with
458 | (r
, Tshape
(shape_kind
, fields
))
459 when String.equal ts
SN.FB.cTypeStructure
->
461 Typing_structure.transform_shapemap
env array_pos
ty fields
463 let ty = mk
(r
, Tshape
(shape_kind
, fields
)) in
467 ~lhs_of_null_coalesce
473 | _
-> error_array env expr_pos
ty1
475 | Tunapplied_alias _
->
476 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
487 error_array env expr_pos
ty1
488 (* Type-check array access as though it is the method
489 * array_get<Tk,Tv>(KeyedContainer<Tk,Tv> $array, Tk $key): Tv
490 * (We can already force Tk to be the type of the key argument because
491 * Tk does not appear in the result of the call)
494 let (env, value) = Env.fresh_type
env expr_pos
in
495 let keyed_container = MakeType.keyed_container r ty2
value in
497 SubType.sub_type
env ty1 keyed_container Errors.index_type_mismatch
501 (* Given a type `ty` known to be a lower bound on the type of the array operand
502 * to an array append operation, compute the largest upper bound on that type
503 * that validates the get operation. For example, if `vec<string>` is a lower
504 * bound, then `vec<#1>` is a suitable upper bound.`
506 let widen_for_assign_array_append ~expr_pos
env ty =
508 (* dynamic is valid for array append *)
509 | (_
, Tdynamic
) -> (env, Some
ty)
510 | (r
, Tclass
(((_
, cn
) as id
), _
, tyl
))
511 when String.equal cn
SN.Collections.cVec
512 || String.equal cn
SN.Collections.cKeyset
513 || String.equal cn
SN.Collections.cVector
514 || String.equal cn
SN.Collections.cMap
->
516 List.map_env
env tyl
(fun env _ty
->
517 Env.fresh_invariant_type_var
env expr_pos
)
519 let ty = mk
(r
, Tclass
(id
, Nonexact
, params
)) in
522 let (env, element_ty
) = Env.fresh_invariant_type_var
env expr_pos
in
523 (env, Some
(mk
(r
, Tvarray element_ty
)))
526 let assign_array_append ~array_pos ~expr_pos ur
env ty1 ty2
=
528 Typing_solver.expand_type_and_narrow
529 ~description_of_expected
:"an array or collection"
531 (widen_for_assign_array_append ~expr_pos
)
536 GenericRules.apply_rules
env ty1 (fun env ty1 ->
538 | (_
, Tany _
) -> (env, ty1)
539 | (_
, Terr
) -> (env, ty1)
540 | (_
, Tclass
((_
, n
), _
, [tv
]))
541 when String.equal n
SN.Collections.cVector
542 || String.equal n
SN.Collections.cSet
->
544 Typing_ops.sub_type expr_pos ur
env ty2 tv
Errors.unify_error
547 (* Handle the case where Vector or Set was used as a typehint
548 without type parameters *)
549 | (_
, Tclass
((_
, n
), _
, []))
550 when String.equal n
SN.Collections.cVector
551 || String.equal n
SN.Collections.cSet
->
553 | (r
, Tclass
(((_
, n
) as id
), e
, [tv
]))
554 when String.equal n
SN.Collections.cVec
555 || String.equal n
SN.Collections.cKeyset
->
556 let (env, tv'
) = Typing_union.union
env tv ty2
in
557 (env, mk
(r
, Tclass
(id
, e
, [tv'
])))
559 let (env, tv'
) = Typing_union.union
env tv ty2
in
560 (env, mk
(r
, Tvarray tv'
))
561 | (_
, Tdynamic
) -> (env, ty1)
563 if Partial.should_check_error
(Env.get_mode
env) 4006 then
564 error_assign_array_append env expr_pos
ty1
567 | (_
, Tunapplied_alias _
) ->
568 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
570 ( Tnonnull
| Tdarray _
| Tvec_or_dict _
| Tvarray_or_darray _
571 | Toption _
| Tprim _
| Tvar _
| Tfun _
| Tclass _
| Ttuple _
572 | Tshape _
| Tunion _
| Tintersection _
| Tgeneric _
| Tnewtype _
573 | Tdependent _
| Taccess _
) ) ->
574 error_assign_array_append env expr_pos
ty1)
576 let widen_for_assign_array_get ~expr_pos index_expr
env ty =
578 log_with_level
env "typing" 1 (fun () ->
582 [Log_head
("widen_for_assign_array_get", [Log_type
("ty", ty)])]));
584 (* dynamic is valid for assign array get *)
585 | (_
, Tdynamic
) -> (env, Some
ty)
586 | (r
, Tclass
(((_
, cn
) as id
), _
, tyl
))
587 when cn
= SN.Collections.cVec
588 || cn
= SN.Collections.cKeyset
589 || cn
= SN.Collections.cVector
590 || cn
= SN.Collections.cDict
591 || cn
= SN.Collections.cMap
->
593 List.map_env
env tyl
(fun env _ty
->
594 Env.fresh_invariant_type_var
env expr_pos
)
596 let ty = mk
(r
, Tclass
(id
, Nonexact
, params
)) in
599 let (env, tv
) = Env.fresh_invariant_type_var
env expr_pos
in
600 (env, Some
(mk
(r
, Tvarray tv
)))
601 | (r
, Tvarray_or_darray _
) ->
602 let (env, tk
) = Env.fresh_invariant_type_var
env expr_pos
in
603 let (env, tv
) = Env.fresh_invariant_type_var
env expr_pos
in
604 (env, Some
(mk
(r
, Tvarray_or_darray
(tk
, tv
))))
606 let (env, tk
) = Env.fresh_invariant_type_var
env expr_pos
in
607 let (env, tv
) = Env.fresh_invariant_type_var
env expr_pos
in
608 (env, Some
(mk
(r
, Tdarray
(tk
, tv
))))
610 (* requires integer literal *)
612 match index_expr
with
613 (* Should freshen type variables *)
616 List.map_env
env tyl
(fun env _ty
->
617 Env.fresh_invariant_type_var
env expr_pos
)
619 (env, Some
(mk
(r
, Ttuple params
)))
624 (* Used for typing an assignment e1[key] = e2
625 * where e1 has type ty1, key has type tkey and e2 has type ty2.
626 * Return the new array type
628 let assign_array_get ~array_pos ~expr_pos ur
env ty1 key tkey ty2
=
630 Typing_solver.expand_type_and_narrow
631 ~description_of_expected
:"an array or collection"
633 (widen_for_assign_array_get ~expr_pos key
)
638 GenericRules.apply_rules
env ety1
(fun env ety1
->
639 let (r
, ety1_
) = deref ety1
in
640 let arity_error (_
, name
) =
641 Errors.array_get_arity expr_pos name
(Reason.to_pos r
)
643 let type_index env p ty_have ty_expect
reason =
644 (* coerce if possible *)
646 Typing_coercion.try_coerce
649 { et_type
= ty_expect
; et_enforced
= true }
653 (* if subtype of dynamic, allow it to be used *)
655 Typing_solver.is_sub_type
env ty_have
(MakeType.dynamic
Reason.none
)
658 (* fail with useful error *)
666 Errors.index_type_mismatch
668 let error = (env, ety1
) in
671 let tk = MakeType.int (Reason.Ridx
(fst key
, r
)) in
672 let env = type_index env expr_pos tkey
tk Reason.index_array
in
673 let (env, tv'
) = Typing_union.union
env tv ty2
in
674 (env, mk
(r
, Tvarray tv'
))
675 | Tclass
(((_
, cn
) as id
), _
, argl
)
676 when String.equal cn
SN.Collections.cVector
->
682 err_witness env expr_pos
684 let tk = MakeType.int (Reason.Ridx_vector
(fst key
)) in
685 let env = type_index env expr_pos tkey
tk (Reason.index_class cn
) in
687 Typing_ops.sub_type expr_pos ur
env ty2
tv Errors.unify_error
690 | Tclass
(((_
, cn
) as id
), e
, argl
)
691 when String.equal cn
SN.Collections.cVec
->
697 err_witness env expr_pos
699 let tk = MakeType.int (Reason.Ridx_vector
(fst key
)) in
700 let env = type_index env expr_pos tkey
tk (Reason.index_class cn
) in
701 let (env, tv'
) = Typing_union.union
env tv ty2
in
702 (env, mk
(r
, Tclass
(id
, e
, [tv'
])))
703 | Tclass
(((_
, cn
) as id
), _
, argl
) when cn
= SN.Collections.cMap
->
704 let env = check_arraykey_index_write env expr_pos ety1 tkey
in
707 | [tk; tv] -> (tk, tv)
710 let any = err_witness env expr_pos
in
713 let env = type_index env expr_pos tkey
tk (Reason.index_class cn
) in
715 Typing_ops.sub_type expr_pos ur
env ty2
tv Errors.unify_error
718 | Tclass
(((_
, cn
) as id
), e
, argl
)
719 when String.equal cn
SN.Collections.cDict
->
720 let env = check_arraykey_index_write env expr_pos ety1 tkey
in
723 | [tk; tv] -> (tk, tv)
726 let any = err_witness env expr_pos
in
729 let (env, tk'
) = Typing_union.union
env tk tkey
in
730 let (env, tv'
) = Typing_union.union
env tv ty2
in
731 (env, mk
(r
, Tclass
(id
, e
, [tk'
; tv'
])))
732 | Tclass
((_
, cn
), _
, _
) when String.equal cn
SN.Collections.cKeyset
->
733 Errors.keyset_set expr_pos
(Reason.to_pos r
);
735 | Tclass
((_
, cn
), _
, _
)
736 when String.equal cn
SN.Collections.cConstMap
737 || String.equal cn
SN.Collections.cImmMap
738 || String.equal cn
SN.Collections.cKeyedContainer
739 || String.equal cn
SN.Collections.cAnyArray
740 || String.equal cn
SN.Collections.cConstVector
741 || String.equal cn
SN.Collections.cImmVector
742 || String.equal cn
SN.Collections.cPair
->
743 Errors.const_mutation
746 (Typing_print.error env ety1
);
748 | Tdarray
(tk, tv) ->
749 let env = check_arraykey_index_write env expr_pos ety1 tkey
in
750 let (env, tk'
) = Typing_union.union
env tk tkey
in
751 let (env, tv'
) = Typing_union.union
env tv ty2
in
752 (env, mk
(r
, Tdarray
(tk'
, tv'
)))
753 | Tvarray_or_darray
(tk, tv) ->
754 let env = check_arraykey_index_write env expr_pos ety1 tkey
in
755 let (env, tk'
) = Typing_union.union
env tk tkey
in
756 let (env, tv'
) = Typing_union.union
env tv ty2
in
757 (env, mk
(r
, Tvarray_or_darray
(tk'
, tv'
)))
758 | Tvec_or_dict
(tk, tv) ->
759 let env = check_arraykey_index_write env expr_pos ety1 tkey
in
760 let (env, tk'
) = Typing_union.union
env tk tkey
in
761 let (env, tv'
) = Typing_union.union
env tv ty2
in
762 (env, mk
(r
, Tvec_or_dict
(tk'
, tv'
)))
764 | Tdynamic
-> (env, ety1
)
765 | Tany _
-> (env, ety1
)
767 let tk = MakeType.int (Reason.Ridx
(fst key
, r
)) in
768 let tv = MakeType.string (Reason.Rwitness expr_pos
) in
769 let env = type_index env expr_pos tkey
tk Reason.index_array
in
771 Typing_ops.sub_type expr_pos ur
env ty2
tv Errors.unify_error
776 Errors.typing_error
(fst key
) (Reason.string_of_ureason
reason);
782 let idx = int_of_string_opt n
in
783 (match Option.map ~f
:(List.split_n tyl
) idx with
784 | Some
(tyl'
, _
:: tyl''
) ->
785 (env, MakeType.tuple r
(tyl'
@ (ty2
:: tyl''
)))
786 | _
-> fail Reason.index_tuple
)
787 | _
-> fail Reason.URtuple_access
789 | Tshape
(shape_kind
, fdm
) ->
791 match TUtils.shape_field_name
env key
with
794 let field = TShapeField.of_ast
(fun p -> p) field in
796 TShapeMap.add
field { sft_optional
= false; sft_ty
= ty2
} fdm
798 (env, mk
(r
, Tshape
(shape_kind
, fdm'
)))
801 if Partial.should_check_error
(Env.get_mode
env) 4370 then (
802 Errors.array_access_write
805 (Typing_print.error env ety1
);
809 | Tunapplied_alias _
->
810 Typing_defs.error_Tunapplied_alias_in_illegal_context
()
823 Errors.array_access_write
826 (Typing_print.error env ety1
);