mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Merge pull request #944 from Microsoft/inOperatorWithUnionTypes
In, for...in, and instanceof operators with union types
This commit is contained in:
commit
4fe28f7e65
@ -4143,8 +4143,8 @@ module ts {
|
||||
// Get the narrowed type of a given symbol at a given location
|
||||
function getNarrowedTypeOfSymbol(symbol: Symbol, node: Node) {
|
||||
var type = getTypeOfSymbol(symbol);
|
||||
// Only narrow when symbol is variable of a non-primitive type
|
||||
if (symbol.flags & SymbolFlags.Variable && isTypeAnyOrObjectOrTypeParameter(type)) {
|
||||
// Only narrow when symbol is variable of a structured type
|
||||
if (symbol.flags & SymbolFlags.Variable && type.flags & TypeFlags.Structured) {
|
||||
while (true) {
|
||||
var child = node;
|
||||
node = node.parent;
|
||||
@ -5679,8 +5679,12 @@ module ts {
|
||||
return numberType;
|
||||
}
|
||||
|
||||
function isTypeAnyOrObjectOrTypeParameter(type: Type): boolean {
|
||||
return (type.flags & (TypeFlags.Any | TypeFlags.ObjectType | TypeFlags.TypeParameter)) !== 0;
|
||||
// Return true if type is any, an object type, a type parameter, or a union type composed of only those kinds of types
|
||||
function isStructuredType(type: Type): boolean {
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
return !forEach((<UnionType>type).types, t => !isStructuredType(t));
|
||||
}
|
||||
return (type.flags & TypeFlags.Structured) !== 0;
|
||||
}
|
||||
|
||||
function checkInstanceOfExpression(node: BinaryExpression, leftType: Type, rightType: Type): Type {
|
||||
@ -5689,7 +5693,7 @@ module ts {
|
||||
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
|
||||
// The result is always of the Boolean primitive type.
|
||||
// NOTE: do not raise error if leftType is unknown as related error was already reported
|
||||
if (leftType !== unknownType && !isTypeAnyOrObjectOrTypeParameter(leftType)) {
|
||||
if (leftType !== unknownType && !isStructuredType(leftType)) {
|
||||
error(node.left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
// NOTE: do not raise error if right is unknown as related error was already reported
|
||||
@ -5707,7 +5711,7 @@ module ts {
|
||||
if (leftType !== anyType && leftType !== stringType && leftType !== numberType) {
|
||||
error(node.left, Diagnostics.The_left_hand_side_of_an_in_expression_must_be_of_types_any_string_or_number);
|
||||
}
|
||||
if (!isTypeAnyOrObjectOrTypeParameter(rightType)) {
|
||||
if (!isStructuredType(rightType)) {
|
||||
error(node.right, Diagnostics.The_right_hand_side_of_an_in_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
return booleanType;
|
||||
@ -6928,7 +6932,7 @@ module ts {
|
||||
var exprType = checkExpression(node.expression);
|
||||
// unknownType is returned i.e. if node.expression is identifier whose name cannot be resolved
|
||||
// in this case error about missing name is already reported - do not report extra one
|
||||
if (!isTypeAnyOrObjectOrTypeParameter(exprType) && exprType !== unknownType) {
|
||||
if (!isStructuredType(exprType) && exprType !== unknownType) {
|
||||
error(node.expression, Diagnostics.The_right_hand_side_of_a_for_in_statement_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
|
||||
|
||||
@ -909,6 +909,7 @@ module ts {
|
||||
StringLike = String | StringLiteral,
|
||||
NumberLike = Number | Enum,
|
||||
ObjectType = Class | Interface | Reference | Tuple | Anonymous,
|
||||
Structured = Any | ObjectType | Union | TypeParameter
|
||||
}
|
||||
|
||||
// Properties common to all types
|
||||
|
||||
@ -7,7 +7,6 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(18,11): error TS2360: The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(19,11): error TS2360: The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(20,11): error TS2360: The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(29,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(30,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(31,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(32,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
@ -16,11 +15,13 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(35,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(36,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(37,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(40,11): error TS2360: The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(40,17): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(38,16): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(39,17): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(43,11): error TS2360: The left-hand side of an 'in' expression must be of types 'any', 'string' or 'number'.
|
||||
tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts(43,17): error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
|
||||
|
||||
==== tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts (20 errors) ====
|
||||
==== tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInvalidOperands.ts (21 errors) ====
|
||||
enum E { a }
|
||||
|
||||
var x: any;
|
||||
@ -66,6 +67,7 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
var b2: boolean;
|
||||
var b3: string;
|
||||
var b4: void;
|
||||
var b5: string | number;
|
||||
|
||||
var rb1 = x in b1;
|
||||
~~
|
||||
@ -79,22 +81,26 @@ tests/cases/conformance/expressions/binaryOperators/inOperator/inOperatorWithInv
|
||||
var rb4 = x in b4;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb5 = x in 0;
|
||||
~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb6 = x in false;
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb7 = x in '';
|
||||
var rb5 = x in b5;
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb8 = x in null;
|
||||
var rb6 = x in 0;
|
||||
~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb7 = x in false;
|
||||
~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb8 = x in '';
|
||||
~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb9 = x in null;
|
||||
~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
var rb9 = x in undefined;
|
||||
~~~~~~~~~
|
||||
var rb10 = x in undefined;
|
||||
~~~~~~~~~
|
||||
!!! error TS2361: The right-hand side of an 'in' expression must be of type 'any', an object type or a type parameter
|
||||
|
||||
|
||||
// both operands are invalid
|
||||
var rc1 = {} in '';
|
||||
~~
|
||||
|
||||
@ -26,16 +26,19 @@ var b1: number;
|
||||
var b2: boolean;
|
||||
var b3: string;
|
||||
var b4: void;
|
||||
var b5: string | number;
|
||||
|
||||
var rb1 = x in b1;
|
||||
var rb2 = x in b2;
|
||||
var rb3 = x in b3;
|
||||
var rb4 = x in b4;
|
||||
var rb5 = x in 0;
|
||||
var rb6 = x in false;
|
||||
var rb7 = x in '';
|
||||
var rb8 = x in null;
|
||||
var rb9 = x in undefined;
|
||||
var rb5 = x in b5;
|
||||
var rb6 = x in 0;
|
||||
var rb7 = x in false;
|
||||
var rb8 = x in '';
|
||||
var rb9 = x in null;
|
||||
var rb10 = x in undefined;
|
||||
|
||||
|
||||
// both operands are invalid
|
||||
var rc1 = {} in '';
|
||||
@ -67,14 +70,16 @@ var b1;
|
||||
var b2;
|
||||
var b3;
|
||||
var b4;
|
||||
var b5;
|
||||
var rb1 = x in b1;
|
||||
var rb2 = x in b2;
|
||||
var rb3 = x in b3;
|
||||
var rb4 = x in b4;
|
||||
var rb5 = x in 0;
|
||||
var rb6 = x in false;
|
||||
var rb7 = x in '';
|
||||
var rb8 = x in null;
|
||||
var rb9 = x in undefined;
|
||||
var rb5 = x in b5;
|
||||
var rb6 = x in 0;
|
||||
var rb7 = x in false;
|
||||
var rb8 = x in '';
|
||||
var rb9 = x in null;
|
||||
var rb10 = x in undefined;
|
||||
// both operands are invalid
|
||||
var rc1 = {} in '';
|
||||
|
||||
@ -21,7 +21,18 @@ var rb2 = x in {};
|
||||
|
||||
function foo<T>(t: T) {
|
||||
var rb3 = x in t;
|
||||
}
|
||||
}
|
||||
|
||||
interface X { x: number }
|
||||
interface Y { y: number }
|
||||
|
||||
var c1: X | Y;
|
||||
var c2: X;
|
||||
var c3: Y;
|
||||
|
||||
var rc1 = x in c1;
|
||||
var rc2 = x in (c2 || c3);
|
||||
|
||||
|
||||
//// [inOperatorWithValidOperands.js]
|
||||
var x;
|
||||
@ -42,3 +53,8 @@ var rb2 = x in {};
|
||||
function foo(t) {
|
||||
var rb3 = x in t;
|
||||
}
|
||||
var c1;
|
||||
var c2;
|
||||
var c3;
|
||||
var rc1 = x in c1;
|
||||
var rc2 = x in (c2 || c3);
|
||||
|
||||
@ -67,3 +67,40 @@ function foo<T>(t: T) {
|
||||
>x : any
|
||||
>t : T
|
||||
}
|
||||
|
||||
interface X { x: number }
|
||||
>X : X
|
||||
>x : number
|
||||
|
||||
interface Y { y: number }
|
||||
>Y : Y
|
||||
>y : number
|
||||
|
||||
var c1: X | Y;
|
||||
>c1 : X | Y
|
||||
>X : X
|
||||
>Y : Y
|
||||
|
||||
var c2: X;
|
||||
>c2 : X
|
||||
>X : X
|
||||
|
||||
var c3: Y;
|
||||
>c3 : Y
|
||||
>Y : Y
|
||||
|
||||
var rc1 = x in c1;
|
||||
>rc1 : boolean
|
||||
>x in c1 : boolean
|
||||
>x : any
|
||||
>c1 : X | Y
|
||||
|
||||
var rc2 = x in (c2 || c3);
|
||||
>rc2 : boolean
|
||||
>x in (c2 || c3) : boolean
|
||||
>x : any
|
||||
>(c2 || c3) : X | Y
|
||||
>c2 || c3 : X | Y
|
||||
>c2 : X
|
||||
>c3 : Y
|
||||
|
||||
|
||||
@ -25,16 +25,19 @@ var b1: number;
|
||||
var b2: boolean;
|
||||
var b3: string;
|
||||
var b4: void;
|
||||
var b5: string | number;
|
||||
|
||||
var rb1 = x in b1;
|
||||
var rb2 = x in b2;
|
||||
var rb3 = x in b3;
|
||||
var rb4 = x in b4;
|
||||
var rb5 = x in 0;
|
||||
var rb6 = x in false;
|
||||
var rb7 = x in '';
|
||||
var rb8 = x in null;
|
||||
var rb9 = x in undefined;
|
||||
var rb5 = x in b5;
|
||||
var rb6 = x in 0;
|
||||
var rb7 = x in false;
|
||||
var rb8 = x in '';
|
||||
var rb9 = x in null;
|
||||
var rb10 = x in undefined;
|
||||
|
||||
|
||||
// both operands are invalid
|
||||
var rc1 = {} in '';
|
||||
@ -20,4 +20,14 @@ var rb2 = x in {};
|
||||
|
||||
function foo<T>(t: T) {
|
||||
var rb3 = x in t;
|
||||
}
|
||||
}
|
||||
|
||||
interface X { x: number }
|
||||
interface Y { y: number }
|
||||
|
||||
var c1: X | Y;
|
||||
var c2: X;
|
||||
var c3: Y;
|
||||
|
||||
var rc1 = x in c1;
|
||||
var rc2 = x in (c2 || c3);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user