Skip to content

Commit

Permalink
[flow][tuples] Inexact tuple types type-checking
Browse files Browse the repository at this point in the history
Summary: Changelog: [internal] Implemented type-checking for inexact tuple types when behind the flag `inexact_tuple_types_syntax=true`. Inexact tuple types allow for additional elements beyond the specified ones, and use the `...` last element syntax. The empty inexact tuple type `[...]` is the supertype of all tuples.

Reviewed By: panagosg7

Differential Revision: D56713879

fbshipit-source-id: 28f4c8a69ee96847d5646f30500ea073f795c770
  • Loading branch information
gkz authored and facebook-github-bot committed May 10, 2024
1 parent b5ba20e commit cd0d359
Show file tree
Hide file tree
Showing 29 changed files with 991 additions and 206 deletions.
2 changes: 2 additions & 0 deletions src/common/errors/error_codes.ml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type error_code =
| DuplicateJsxDecl
| DuplicateJsxRuntimeDecl
| DuplicateModule
| ElementAfterInexactTupleSpread
| EmptyArrayNoAnnot
| EnumValueAsType
| ExponentialSpread
Expand Down Expand Up @@ -249,6 +250,7 @@ let string_of_code : error_code -> string = function
| DuplicateJsxDecl -> "duplicate-jsx-decl"
| DuplicateJsxRuntimeDecl -> "duplicate-jsx-runtime-decl"
| DuplicateModule -> "duplicate-module"
| ElementAfterInexactTupleSpread -> "element-after-inexact-tuple-spread"
| EnumValueAsType -> "enum-value-as-type"
| ExponentialSpread -> "exponential-spread"
| ExportRenamedDefault -> "export-renamed-default"
Expand Down
14 changes: 9 additions & 5 deletions src/common/reason.ml
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ type 'loc virtual_reason_desc =
| RTupleElement of { name: string option }
| RTupleLength of int
| RTupleOutOfBoundsAccess of int
| RTupleUnknownElementFromInexact
| RFunction of reason_desc_function
| RFunctionType
| RFunctionBody
Expand Down Expand Up @@ -278,11 +279,12 @@ let rec map_desc_locs f = function
| RNumberLit _ | RBigIntLit _ | RBooleanLit _ | RObject | RConstObjectLit | RObjectLit
| RObjectType | RObjectClassName | RInterfaceType | RArray | RArrayLit | RConstArrayLit
| REmptyArrayLit | RArrayType | RArrayElement | RArrayNthElement _ | RROArrayType | RTupleType
| RTupleElement _ | RTupleLength _ | RTupleOutOfBoundsAccess _ | RFunction _ | RFunctionType
| RFunctionBody | RFunctionCallType | RFunctionUnusedArgument | RJSXChild | RJSXFunctionCall _
| RJSXIdentifier _ | RJSXElementProps _ | RJSXElement _ | RJSXText | RFbt | RUninitialized
| RPossiblyUninitialized | RUnannotatedNext | REmptyArrayElement | RMappedType | RTypeGuard
| RTypeGuardParam _ | RComponent _ | RComponentType | RInferredUnionElemArray _ ) as r ->
| RTupleElement _ | RTupleLength _ | RTupleOutOfBoundsAccess _ | RTupleUnknownElementFromInexact
| RFunction _ | RFunctionType | RFunctionBody | RFunctionCallType | RFunctionUnusedArgument
| RJSXChild | RJSXFunctionCall _ | RJSXIdentifier _ | RJSXElementProps _ | RJSXElement _
| RJSXText | RFbt | RUninitialized | RPossiblyUninitialized | RUnannotatedNext
| REmptyArrayElement | RMappedType | RTypeGuard | RTypeGuardParam _ | RComponent _
| RComponentType | RInferredUnionElemArray _ ) as r ->
r
| RFunctionCall desc -> RFunctionCall (map_desc_locs f desc)
| RUnknownUnspecifiedProperty desc -> RUnknownUnspecifiedProperty (map_desc_locs f desc)
Expand Down Expand Up @@ -605,6 +607,7 @@ let rec string_of_desc = function
in
spf "%s%s" "tuple element" suffix
| RTupleOutOfBoundsAccess i -> spf "undefined (out of bounds tuple access at index %d)" i
| RTupleUnknownElementFromInexact -> "an unknown element of an inexact tuple type"
| RTupleLength i -> spf "length `%d` (number) of tuple" i
| RFunction func -> spf "%sfunction" (function_desc_prefix func)
| RFunctionType -> "function type"
Expand Down Expand Up @@ -1425,6 +1428,7 @@ let classification_of_reason_desc desc =
| RTupleElement _
| RTupleLength _
| RTupleOutOfBoundsAccess _
| RTupleUnknownElementFromInexact
| RComponent _
| RComponentType
| RPropsOfComponent _
Expand Down
1 change: 1 addition & 0 deletions src/common/reason.mli
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type 'loc virtual_reason_desc =
| RTupleElement of { name: string option }
| RTupleLength of int
| RTupleOutOfBoundsAccess of int
| RTupleUnknownElementFromInexact
| RFunction of reason_desc_function
| RFunctionType
| RFunctionBody
Expand Down
11 changes: 7 additions & 4 deletions src/typing/annotation_inference.ml
Original file line number Diff line number Diff line change
Expand Up @@ -961,10 +961,13 @@ module rec ConsGen : S = struct
(************)
| (DefT (r, ObjT ({ Type.flags; _ } as o)), Annot_DeepReadOnlyT (_, dro_loc, dro_kind)) ->
DefT (r, ObjT { o with Type.flags = { flags with react_dro = Some (dro_loc, dro_kind) } })
| ( DefT (r, ArrT (TupleAT { elem_t; elements; arity; react_dro = _ })),
| ( DefT (r, ArrT (TupleAT { elem_t; elements; arity; inexact; react_dro = _ })),
Annot_DeepReadOnlyT (_, dro_loc, dro_kind)
) ->
DefT (r, ArrT (TupleAT { elem_t; elements; arity; react_dro = Some (dro_loc, dro_kind) }))
DefT
( r,
ArrT (TupleAT { elem_t; elements; arity; inexact; react_dro = Some (dro_loc, dro_kind) })
)
| ( DefT (r, ArrT (ArrayAT { elem_t; tuple_view; react_dro = _ })),
Annot_DeepReadOnlyT (_, dro_loc, dro_kind)
) ->
Expand Down Expand Up @@ -1195,10 +1198,10 @@ module rec ConsGen : S = struct
| (DefT (reason, ArrT (ArrayAT { elem_t; _ })), (Annot_GetPropT _ | Annot_LookupT _)) ->
let arr = get_builtin_typeapp cx reason "Array" [elem_t] in
elab_t cx arr op
| ( DefT (reason, ArrT (TupleAT { arity; _ })),
| ( DefT (reason, ArrT (TupleAT { arity; inexact; _ })),
Annot_GetPropT (reason_op, _, Named { name = OrdinaryName "length"; _ })
) ->
GetPropTKit.on_array_length cx dummy_trace reason arity reason_op
GetPropTKit.on_array_length cx dummy_trace reason ~inexact arity reason_op
| ( DefT (reason, ArrT ((TupleAT _ | ROArrayAT _) as arrtype)),
(Annot_GetPropT _ | Annot_LookupT _)
) ->
Expand Down
23 changes: 18 additions & 5 deletions src/typing/debug_js.ml
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,11 @@ let rec dump_t_ (depth, tvars) cx t =
( _,
ArrT
(ArrayAT
{ elem_t; tuple_view = Some (TupleView { elements; arity = _ }); react_dro = _ }
{
elem_t;
tuple_view = Some (TupleView { elements; arity = _; inexact = _ });
react_dro = _;
}
)
) ->
p
Expand Down Expand Up @@ -896,7 +900,7 @@ and dump_use_t_ (depth, tvars) cx t =
p t ~extra:(spf "use_desc=%b, %s" use_desc (use_kid (UseT (use_op, arg))))
| ResolveSpreadT (use_op, _, { rrt_resolve_to; _ }) ->
(match rrt_resolve_to with
| ResolveSpreadsToTupleType { id = _; elem_t; tout }
| ResolveSpreadsToTupleType { id = _; inexact = _; elem_t; tout }
| ResolveSpreadsToArrayLiteral { elem_t; tout; _ }
| ResolveSpreadsToArray (elem_t, tout) ->
p ~extra:(spf "%s, %s, %s" (string_of_use_op use_op) (kid elem_t) (kid tout)) t
Expand Down Expand Up @@ -1388,17 +1392,23 @@ let dump_error_message =
use_op;
lower_reason;
lower_arity = (num_req1, num_total1);
lower_inexact;
upper_reason;
upper_arity = (num_req2, num_total2);
upper_inexact;
unify;
} ->
spf
"ETupleArityMismatch (%s, %s, %d-%d, %d-%d, %s)"
"ETupleArityMismatch (%s, %s, %d-%d inexact:%b, %d-%d inexact:%b, unify:%b, %s)"
(dump_reason cx lower_reason)
(dump_reason cx upper_reason)
num_req1
num_total1
lower_inexact
num_req2
num_total2
upper_inexact
unify
(string_of_use_op use_op)
| ENonLitArrayToTuple ((reason1, reason2), use_op) ->
spf
Expand All @@ -1417,12 +1427,13 @@ let dump_error_message =
"ETupleInvalidTypeSpread {reason_spread = %s; reason_arg = %s}"
(dump_reason cx reason_spread)
(dump_reason cx reason_arg)
| ETupleOutOfBounds { use_op; reason; reason_op; length; index } ->
| ETupleOutOfBounds { use_op; reason; reason_op; inexact; length; index } ->
spf
"ETupleOutOfBounds { use_op = %s; reason = %s; reason_op = %s; length = %d; index = %s }"
"ETupleOutOfBounds { use_op = %s; reason = %s; reason_op = %s; inexact = %b; length = %d; index = %s }"
(string_of_use_op use_op)
(dump_reason cx reason)
(dump_reason cx reason_op)
inexact
length
index
| ETupleNonIntegerIndex { use_op; reason; index } ->
Expand Down Expand Up @@ -1458,6 +1469,8 @@ let dump_error_message =
(dump_reason cx reason_upper)
(Polarity.string polarity_upper)
(string_of_use_op use_op)
| ETupleElementAfterInexactSpread reason ->
spf "ETupleElementAfterInexactSpread (%s)" (dump_reason cx reason)
| EROArrayWrite ((reason1, reason2), use_op) ->
spf
"EROArrayWrite (%s, %s, %s)"
Expand Down
85 changes: 75 additions & 10 deletions src/typing/errors/error_message.ml
Original file line number Diff line number Diff line change
Expand Up @@ -121,14 +121,18 @@ and 'loc t' =
use_op: 'loc virtual_use_op;
lower_reason: 'loc virtual_reason;
lower_arity: int * int;
lower_inexact: bool;
upper_reason: 'loc virtual_reason;
upper_arity: int * int;
upper_inexact: bool;
unify: bool;
}
| ENonLitArrayToTuple of ('loc virtual_reason * 'loc virtual_reason) * 'loc virtual_use_op
| ETupleOutOfBounds of {
use_op: 'loc virtual_use_op;
reason: 'loc virtual_reason;
reason_op: 'loc virtual_reason;
inexact: bool;
length: int;
index: string;
}
Expand Down Expand Up @@ -170,6 +174,7 @@ and 'loc t' =
reason_spread: 'loc virtual_reason;
reason_arg: 'loc virtual_reason;
}
| ETupleElementAfterInexactSpread of 'loc virtual_reason
| EROArrayWrite of ('loc virtual_reason * 'loc virtual_reason) * 'loc virtual_use_op
| EUnionSpeculationFailed of {
use_op: 'loc virtual_use_op;
Expand Down Expand Up @@ -837,23 +842,37 @@ let rec map_loc_of_error_message (f : 'a -> 'b) : 'a t' -> 'b t' =
EPrivateLookupFailed ((map_reason r1, map_reason r2), x, map_use_op op)
| EPlatformSpecificImplementationModuleLookupFailed { loc; name } ->
EPlatformSpecificImplementationModuleLookupFailed { loc = f loc; name }
| ETupleArityMismatch { use_op; lower_reason; lower_arity; upper_reason; upper_arity } ->
| ETupleArityMismatch
{
use_op;
lower_reason;
lower_arity;
lower_inexact;
upper_reason;
upper_arity;
upper_inexact;
unify;
} ->
ETupleArityMismatch
{
use_op = map_use_op use_op;
lower_reason = map_reason lower_reason;
lower_arity;
lower_inexact;
upper_reason = map_reason upper_reason;
upper_arity;
upper_inexact;
unify;
}
| ENonLitArrayToTuple ((r1, r2), op) ->
ENonLitArrayToTuple ((map_reason r1, map_reason r2), map_use_op op)
| ETupleOutOfBounds { use_op; reason; reason_op; length; index } ->
| ETupleOutOfBounds { use_op; reason; reason_op; inexact; length; index } ->
ETupleOutOfBounds
{
use_op = map_use_op use_op;
reason = map_reason reason;
reason_op = map_reason reason_op;
inexact;
length;
index;
}
Expand Down Expand Up @@ -886,6 +905,7 @@ let rec map_loc_of_error_message (f : 'a -> 'b) : 'a t' -> 'b t' =
| ETupleInvalidTypeSpread { reason_spread; reason_arg } ->
ETupleInvalidTypeSpread
{ reason_spread = map_reason reason_spread; reason_arg = map_reason reason_arg }
| ETupleElementAfterInexactSpread reason -> ETupleElementAfterInexactSpread (map_reason reason)
| EROArrayWrite ((r1, r2), op) -> EROArrayWrite ((map_reason r1, map_reason r2), map_use_op op)
| EUnionSpeculationFailed { use_op; reason; op_reasons; branches } ->
EUnionSpeculationFailed
Expand Down Expand Up @@ -1360,13 +1380,35 @@ let util_use_op_of_msg nope util = function
| EPropPolarityMismatch (rs, p, ps, op) ->
util op (fun op -> EPropPolarityMismatch (rs, p, ps, op))
| EPrivateLookupFailed (rs, x, op) -> util op (fun op -> EPrivateLookupFailed (rs, x, op))
| ETupleArityMismatch { use_op; lower_reason; lower_arity; upper_reason; upper_arity } ->
| ETupleArityMismatch
{
use_op;
lower_reason;
lower_arity;
lower_inexact;
upper_reason;
upper_arity;
upper_inexact;
unify;
} ->
util use_op (fun use_op ->
ETupleArityMismatch { use_op; lower_reason; lower_arity; upper_reason; upper_arity }
ETupleArityMismatch
{
use_op;
lower_reason;
lower_arity;
lower_inexact;
upper_reason;
upper_arity;
upper_inexact;
unify;
}
)
| ENonLitArrayToTuple (rs, op) -> util op (fun op -> ENonLitArrayToTuple (rs, op))
| ETupleOutOfBounds { use_op; reason; reason_op; length; index } ->
util use_op (fun use_op -> ETupleOutOfBounds { use_op; reason; reason_op; length; index })
| ETupleOutOfBounds { use_op; reason; reason_op; inexact; length; index } ->
util use_op (fun use_op ->
ETupleOutOfBounds { use_op; reason; reason_op; inexact; length; index }
)
| ETupleNonIntegerIndex { use_op; reason; index } ->
util use_op (fun use_op -> ETupleNonIntegerIndex { use_op; reason; index })
| ETupleUnsafeWrite { reason; use_op } ->
Expand Down Expand Up @@ -1572,6 +1614,7 @@ let util_use_op_of_msg nope util = function
| EInvalidMappedType _
| ETupleRequiredAfterOptional _
| ETupleInvalidTypeSpread _
| ETupleElementAfterInexactSpread _
| ETypeGuardParamUnbound _
| ETypeGuardFunctionParamHavoced _
| ETypeGuardIncompatibleWithFunctionKind _
Expand Down Expand Up @@ -1648,6 +1691,7 @@ let loc_of_msg : 'loc t' -> 'loc option = function
| EInvalidBinaryArith { reason_out = reason; _ }
| ETupleRequiredAfterOptional { reason_tuple = reason; _ }
| ETupleInvalidTypeSpread { reason_spread = reason; _ }
| ETupleElementAfterInexactSpread reason
| EPredicateInvalidParameter { pred_reason = reason; _ }
| ETypeGuardParamUnbound reason
| ETypeGuardFunctionInvalidWrites { reason; _ }
Expand Down Expand Up @@ -2155,12 +2199,31 @@ let friendly_message_of_msg = function
| EComparison (lower, upper) -> Normal (MessageCannotCompare { lower; upper })
| ENonStrictEqualityComparison (lower, upper) ->
Normal (MessageCannotCompareNonStrict { lower; upper })
| ETupleArityMismatch { use_op; lower_reason; lower_arity; upper_reason; upper_arity } ->
| ETupleArityMismatch
{
use_op;
lower_reason;
lower_arity;
lower_inexact;
upper_reason;
upper_arity;
upper_inexact;
unify;
} ->
UseOp
{
loc = loc_of_reason lower_reason;
message =
MessageIncompatibleTupleArity { lower_reason; lower_arity; upper_reason; upper_arity };
MessageIncompatibleTupleArity
{
lower_reason;
lower_arity;
lower_inexact;
upper_reason;
upper_arity;
upper_inexact;
unify;
};
use_op;
explanation = None;
}
Expand All @@ -2169,6 +2232,7 @@ let friendly_message_of_msg = function
(MessageInvalidTupleRequiredAfterOptional { reason_tuple; reason_required; reason_optional })
| ETupleInvalidTypeSpread { reason_arg; reason_spread = _ } ->
Normal (MessageInvalidTupleTypeSpread reason_arg)
| ETupleElementAfterInexactSpread _ -> Normal MessageTupleElementAfterInexactSpread
| ENonLitArrayToTuple ((lower, upper), use_op) ->
UseOp
{
Expand All @@ -2177,11 +2241,11 @@ let friendly_message_of_msg = function
use_op;
explanation = None;
}
| ETupleOutOfBounds { reason; reason_op; length; index; use_op } ->
| ETupleOutOfBounds { reason; reason_op; inexact; length; index; use_op } ->
UseOp
{
loc = loc_of_reason reason;
message = MessageTupleIndexOutOfBound { reason_op; length; index };
message = MessageTupleIndexOutOfBound { reason_op; inexact; length; index };
use_op;
explanation = None;
}
Expand Down Expand Up @@ -2965,6 +3029,7 @@ let error_code_of_message err : error_code option =
| ETupleArityMismatch _ -> Some InvalidTupleArity
| ETupleRequiredAfterOptional _ -> Some TupleRequiredAfterOptional
| ETupleInvalidTypeSpread _ -> Some TupleInvalidTypeSpread
| ETupleElementAfterInexactSpread _ -> Some ElementAfterInexactTupleSpread
| ETupleElementNotReadable _ -> Some CannotRead
| ETupleElementNotWritable _ -> Some CannotWrite
| ETupleElementPolarityMismatch _ -> Some IncompatibleVariance
Expand Down

0 comments on commit cd0d359

Please sign in to comment.