Merge pull request #428 from Microsoft/tupleTypes
Adding support for tuple types (e.g. [number, string])
This commit is contained in:
commit
11b9118cab
|
@ -102,6 +102,7 @@ module ts {
|
|||
var globalBooleanType: ObjectType;
|
||||
var globalRegExpType: ObjectType;
|
||||
|
||||
var tupleTypes: Map<TupleType> = {};
|
||||
var stringLiteralTypes: Map<StringLiteralType> = {};
|
||||
var emitExtends = false;
|
||||
|
||||
|
@ -649,15 +650,14 @@ module ts {
|
|||
}
|
||||
|
||||
function isOptionalProperty(propertySymbol: Symbol): boolean {
|
||||
if (propertySymbol.flags & SymbolFlags.Prototype) {
|
||||
return false;
|
||||
}
|
||||
// class C {
|
||||
// constructor(public x?) { }
|
||||
// }
|
||||
//
|
||||
// x is an optional parameter, but it is a required property.
|
||||
return (propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark) && propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
|
||||
return propertySymbol.valueDeclaration &&
|
||||
propertySymbol.valueDeclaration.flags & NodeFlags.QuestionMark &&
|
||||
propertySymbol.valueDeclaration.kind !== SyntaxKind.Parameter;
|
||||
}
|
||||
|
||||
function forEachSymbolTableInScope<T>(enclosingDeclaration: Node, callback: (symbolTable: SymbolTable) => T): T {
|
||||
|
@ -995,6 +995,9 @@ module ts {
|
|||
else if (type.flags & (TypeFlags.Class | TypeFlags.Interface | TypeFlags.Enum | TypeFlags.TypeParameter)) {
|
||||
writer.writeSymbol(type.symbol, enclosingDeclaration, SymbolFlags.Type);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Tuple) {
|
||||
writeTupleType(<TupleType>type);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Anonymous) {
|
||||
writeAnonymousType(<ObjectType>type, allowFunctionOrConstructorTypeLiteral);
|
||||
}
|
||||
|
@ -1007,6 +1010,15 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
function writeTypeList(types: Type[]) {
|
||||
for (var i = 0; i < types.length; i++) {
|
||||
if (i > 0) {
|
||||
writer.write(", ");
|
||||
}
|
||||
writeType(types[i], /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
}
|
||||
}
|
||||
|
||||
function writeTypeReference(type: TypeReference) {
|
||||
if (type.target === globalArrayType && !(flags & TypeFormatFlags.WriteArrayAsGenericType)) {
|
||||
// If we are writing array element type the arrow style signatures are not allowed as
|
||||
|
@ -1017,16 +1029,17 @@ module ts {
|
|||
else {
|
||||
writer.writeSymbol(type.target.symbol, enclosingDeclaration, SymbolFlags.Type);
|
||||
writer.write("<");
|
||||
for (var i = 0; i < type.typeArguments.length; i++) {
|
||||
if (i > 0) {
|
||||
writer.write(", ");
|
||||
}
|
||||
writeType(type.typeArguments[i], /*allowFunctionOrConstructorTypeLiteral*/ true);
|
||||
}
|
||||
writeTypeList(type.typeArguments);
|
||||
writer.write(">");
|
||||
}
|
||||
}
|
||||
|
||||
function writeTupleType(type: TupleType) {
|
||||
writer.write("[");
|
||||
writeTypeList(type.elementTypes);
|
||||
writer.write("]");
|
||||
}
|
||||
|
||||
function writeAnonymousType(type: ObjectType, allowFunctionOrConstructorTypeLiteral: boolean) {
|
||||
// Always use 'typeof T' for type of class, enum, and module objects
|
||||
if (type.symbol && type.symbol.flags & (SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
|
||||
|
@ -1832,6 +1845,23 @@ module ts {
|
|||
return [createSignature(undefined, classType.typeParameters, emptyArray, classType, 0, false, false)];
|
||||
}
|
||||
|
||||
function createTupleTypeMemberSymbols(memberTypes: Type[]): SymbolTable {
|
||||
var members: SymbolTable = {};
|
||||
for (var i = 0; i < memberTypes.length; i++) {
|
||||
var symbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, "" + i);
|
||||
symbol.type = memberTypes[i];
|
||||
members[i] = symbol;
|
||||
}
|
||||
return members;
|
||||
}
|
||||
|
||||
function resolveTupleTypeMembers(type: TupleType) {
|
||||
var arrayType = resolveObjectTypeMembers(createArrayType(getBestCommonType(type.elementTypes)));
|
||||
var members = createTupleTypeMemberSymbols(type.elementTypes);
|
||||
addInheritedMembers(members, arrayType.properties);
|
||||
setObjectTypeMembers(type, members, arrayType.callSignatures, arrayType.constructSignatures, arrayType.stringIndexType, arrayType.numberIndexType);
|
||||
}
|
||||
|
||||
function resolveAnonymousTypeMembers(type: ObjectType) {
|
||||
var symbol = type.symbol;
|
||||
if (symbol.flags & SymbolFlags.TypeLiteral) {
|
||||
|
@ -1877,6 +1907,9 @@ module ts {
|
|||
else if (type.flags & TypeFlags.Anonymous) {
|
||||
resolveAnonymousTypeMembers(<ObjectType>type);
|
||||
}
|
||||
else if (type.flags & TypeFlags.Tuple) {
|
||||
resolveTupleTypeMembers(<TupleType>type);
|
||||
}
|
||||
else {
|
||||
resolveTypeReferenceMembers(<TypeReference>type);
|
||||
}
|
||||
|
@ -2241,7 +2274,7 @@ module ts {
|
|||
if (type.flags & (TypeFlags.Class | TypeFlags.Interface) && type.flags & TypeFlags.Reference) {
|
||||
var typeParameters = (<InterfaceType>type).typeParameters;
|
||||
if (node.typeArguments && node.typeArguments.length === typeParameters.length) {
|
||||
type = createTypeReference(<GenericType>type, map(node.typeArguments, t => getTypeFromTypeNode(t)));
|
||||
type = createTypeReference(<GenericType>type, map(node.typeArguments, getTypeFromTypeNode));
|
||||
}
|
||||
else {
|
||||
error(node, Diagnostics.Generic_type_0_requires_1_type_argument_s, typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType), typeParameters.length);
|
||||
|
@ -2327,6 +2360,24 @@ module ts {
|
|||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function createTupleType(elementTypes: Type[]) {
|
||||
var id = getTypeListId(elementTypes);
|
||||
var type = tupleTypes[id];
|
||||
if (!type) {
|
||||
type = tupleTypes[id] = <TupleType>createObjectType(TypeFlags.Tuple);
|
||||
type.elementTypes = elementTypes;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
|
||||
var links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromTypeLiteralNode(node: TypeLiteralNode): Type {
|
||||
var links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
|
@ -2371,6 +2422,8 @@ module ts {
|
|||
return getTypeFromTypeQueryNode(<TypeQueryNode>node);
|
||||
case SyntaxKind.ArrayType:
|
||||
return getTypeFromArrayTypeNode(<ArrayTypeNode>node);
|
||||
case SyntaxKind.TupleType:
|
||||
return getTypeFromTupleTypeNode(<TupleTypeNode>node);
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return getTypeFromTypeLiteralNode(<TypeLiteralNode>node);
|
||||
// This function assumes that an identifier or qualified name is a type expression
|
||||
|
@ -2532,6 +2585,9 @@ module ts {
|
|||
if (type.flags & TypeFlags.Reference) {
|
||||
return createTypeReference((<TypeReference>type).target, instantiateList((<TypeReference>type).typeArguments, mapper, instantiateType));
|
||||
}
|
||||
if (type.flags & TypeFlags.Tuple) {
|
||||
return createTupleType(instantiateList((<TupleType>type).elementTypes, mapper, instantiateType));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
@ -3182,7 +3238,6 @@ module ts {
|
|||
while (isArrayType(type)) {
|
||||
type = (<GenericType>type).typeArguments[0];
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -3331,9 +3386,9 @@ module ts {
|
|||
inferFromTypes(sourceTypes[i], targetTypes[i]);
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.ObjectType && (target.flags & TypeFlags.Reference || (target.flags & TypeFlags.Anonymous) &&
|
||||
target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) {
|
||||
// If source is an object type, and target is a type reference, the type of a method, or a type literal, infer from members
|
||||
else if (source.flags & TypeFlags.ObjectType && (target.flags & (TypeFlags.Reference | TypeFlags.Tuple) ||
|
||||
(target.flags & TypeFlags.Anonymous) && target.symbol && target.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral))) {
|
||||
// If source is an object type, and target is a type reference, a tuple type, the type of a method, or a type literal, infer from members
|
||||
if (!isInProcess(source, target) && isWithinDepthLimit(source, sourceStack) && isWithinDepthLimit(target, targetStack)) {
|
||||
if (depth === 0) {
|
||||
sourceStack = [];
|
||||
|
@ -3684,6 +3739,10 @@ module ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// In a variable, parameter or property declaration with a type annotation, the contextual type of an initializer
|
||||
// expression is the type of the variable, parameter or property. In a parameter declaration of a contextually
|
||||
// typed function expression, the contextual type of an initializer expression is the contextual type of the
|
||||
// parameter.
|
||||
function getContextualTypeForInitializerExpression(node: Expression): Type {
|
||||
var declaration = <VariableDeclaration>node.parent;
|
||||
if (node === declaration.initializer) {
|
||||
|
@ -3715,6 +3774,7 @@ module ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// In a typed function call, an argument expression is contextually typed by the type of the corresponding parameter.
|
||||
function getContextualTypeForArgument(node: Expression): Type {
|
||||
var callExpression = <CallExpression>node.parent;
|
||||
var argIndex = indexOf(callExpression.arguments, node);
|
||||
|
@ -3729,11 +3789,14 @@ module ts {
|
|||
var binaryExpression = <BinaryExpression>node.parent;
|
||||
var operator = binaryExpression.operator;
|
||||
if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) {
|
||||
// In an assignment expression, the right operand is contextually typed by the type of the left operand.
|
||||
if (node === binaryExpression.right) {
|
||||
return checkExpression(binaryExpression.left);
|
||||
}
|
||||
}
|
||||
else if (operator === SyntaxKind.BarBarToken) {
|
||||
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
|
||||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand.
|
||||
var type = getContextualType(binaryExpression);
|
||||
if (!type && node === binaryExpression.right) {
|
||||
type = checkExpression(binaryExpression.left);
|
||||
|
@ -3743,6 +3806,9 @@ module ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
|
||||
// the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
|
||||
// exists. Otherwise, it is the type of the string index signature in T, if one exists.
|
||||
function getContextualTypeForPropertyExpression(node: Expression): Type {
|
||||
var declaration = <PropertyDeclaration>node.parent;
|
||||
var objectLiteral = <ObjectLiteral>declaration.parent;
|
||||
|
@ -3758,17 +3824,31 @@ module ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// In an array literal contextually typed by a type T, the contextual type of an element expression at index N is
|
||||
// the type of the property with the numeric name N in T, if one exists. Otherwise, it is the type of the numeric
|
||||
// index signature in T, if one exists.
|
||||
function getContextualTypeForElementExpression(node: Expression): Type {
|
||||
var arrayLiteral = <ArrayLiteral>node.parent;
|
||||
var type = getContextualType(arrayLiteral);
|
||||
return type ? getIndexTypeOfType(type, IndexKind.Number) : undefined;
|
||||
if (type) {
|
||||
var index = indexOf(arrayLiteral.elements, node);
|
||||
var prop = getPropertyOfType(type, "" + index);
|
||||
if (prop) {
|
||||
return getTypeOfSymbol(prop);
|
||||
}
|
||||
return getIndexTypeOfType(type, IndexKind.Number);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
|
||||
function getContextualTypeForConditionalOperand(node: Expression): Type {
|
||||
var conditional = <ConditionalExpression>node.parent;
|
||||
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
||||
}
|
||||
|
||||
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
||||
// be "pushed" onto a node using the contextualType property.
|
||||
function getContextualType(node: Expression): Type {
|
||||
if (node.contextualType) {
|
||||
return node.contextualType;
|
||||
|
@ -3820,17 +3900,26 @@ module ts {
|
|||
}
|
||||
|
||||
function checkArrayLiteral(node: ArrayLiteral, contextualMapper?: TypeMapper): Type {
|
||||
var contextualType = getContextualType(node);
|
||||
var elements = node.elements;
|
||||
var elementTypes: Type[] = [];
|
||||
forEach(node.elements, element => {
|
||||
if (element.kind !== SyntaxKind.OmittedExpression) {
|
||||
var type = checkExpression(element, contextualMapper);
|
||||
if (!contains(elementTypes, type)) elementTypes.push(type);
|
||||
var isTupleLiteral: boolean = false;
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (contextualType && getPropertyOfType(contextualType, "" + i)) {
|
||||
isTupleLiteral = true;
|
||||
}
|
||||
});
|
||||
var contextualType = isInferentialContext(contextualMapper) ? undefined : getContextualType(node);
|
||||
var contextualElementType = contextualType && getIndexTypeOfType(contextualType, IndexKind.Number);
|
||||
var elementType = getBestCommonType(elementTypes, contextualElementType, true);
|
||||
if (!elementType) elementType = elementTypes.length ? emptyObjectType : undefinedType;
|
||||
var element = elements[i];
|
||||
var type = element.kind !== SyntaxKind.OmittedExpression ? checkExpression(element, contextualMapper) : undefinedType;
|
||||
elementTypes.push(type);
|
||||
}
|
||||
if (isTupleLiteral) {
|
||||
return createTupleType(elementTypes);
|
||||
}
|
||||
var contextualElementType = contextualType && !isInferentialContext(contextualMapper) ? getIndexTypeOfType(contextualType, IndexKind.Number) : undefined;
|
||||
var elementType = getBestCommonType(uniqueElements(elementTypes), contextualElementType, true);
|
||||
if (!elementType) {
|
||||
elementType = elements.length ? emptyObjectType : undefinedType;
|
||||
}
|
||||
return createArrayType(elementType);
|
||||
}
|
||||
|
||||
|
@ -3898,12 +3987,14 @@ module ts {
|
|||
}
|
||||
}
|
||||
|
||||
// If a symbol is a synthesized symbol with no value declaration, we assume it is a property. Example of this are the synthesized
|
||||
// '.prototype' property as well as synthesized tuple index properties.
|
||||
function getDeclarationKindFromSymbol(s: Symbol) {
|
||||
return s.flags & SymbolFlags.Prototype ? SyntaxKind.Property : s.valueDeclaration.kind;
|
||||
return s.valueDeclaration ? s.valueDeclaration.kind : SyntaxKind.Property;
|
||||
}
|
||||
|
||||
function getDeclarationFlagsFromSymbol(s: Symbol) {
|
||||
return s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : s.valueDeclaration.flags;
|
||||
return s.valueDeclaration ? s.valueDeclaration.flags : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0;
|
||||
}
|
||||
|
||||
function checkPropertyAccess(node: PropertyAccess) {
|
||||
|
@ -5171,7 +5262,11 @@ module ts {
|
|||
}
|
||||
|
||||
function checkArrayType(node: ArrayTypeNode) {
|
||||
getTypeFromArrayTypeNode(node);
|
||||
checkSourceElement(node.elementType);
|
||||
}
|
||||
|
||||
function checkTupleType(node: TupleTypeNode) {
|
||||
forEach(node.elementTypes, checkSourceElement);
|
||||
}
|
||||
|
||||
function isPrivateWithinAmbient(node: Node): boolean {
|
||||
|
@ -6420,6 +6515,8 @@ module ts {
|
|||
return checkTypeLiteral(<TypeLiteralNode>node);
|
||||
case SyntaxKind.ArrayType:
|
||||
return checkArrayType(<ArrayTypeNode>node);
|
||||
case SyntaxKind.TupleType:
|
||||
return checkTupleType(<TupleTypeNode>node);
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
return checkFunctionDeclaration(<FunctionDeclaration>node);
|
||||
case SyntaxKind.Block:
|
||||
|
|
|
@ -19,8 +19,7 @@ module ts {
|
|||
|
||||
export function contains<T>(array: T[], value: T): boolean {
|
||||
if (array) {
|
||||
var len = array.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
for (var i = 0, len = array.length; i < len; i++) {
|
||||
if (array[i] === value) {
|
||||
return true;
|
||||
}
|
||||
|
@ -31,8 +30,7 @@ module ts {
|
|||
|
||||
export function indexOf<T>(array: T[], value: T): number {
|
||||
if (array) {
|
||||
var len = array.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
for (var i = 0, len = array.length; i < len; i++) {
|
||||
if (array[i] === value) {
|
||||
return i;
|
||||
}
|
||||
|
@ -42,9 +40,8 @@ module ts {
|
|||
}
|
||||
|
||||
export function filter<T>(array: T[], f: (x: T) => boolean): T[] {
|
||||
var result: T[];
|
||||
if (array) {
|
||||
result = [];
|
||||
var result: T[] = [];
|
||||
for (var i = 0, len = array.length; i < len; i++) {
|
||||
var item = array[i];
|
||||
if (f(item)) {
|
||||
|
@ -56,11 +53,9 @@ module ts {
|
|||
}
|
||||
|
||||
export function map<T, U>(array: T[], f: (x: T) => U): U[] {
|
||||
var result: U[];
|
||||
if (array) {
|
||||
result = [];
|
||||
var len = array.length;
|
||||
for (var i = 0; i < len; i++) {
|
||||
var result: U[] = [];
|
||||
for (var i = 0, len = array.length; i < len; i++) {
|
||||
result.push(f(array[i]));
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +68,17 @@ module ts {
|
|||
return array1.concat(array2);
|
||||
}
|
||||
|
||||
export function uniqueElements<T>(array: T[]): T[] {
|
||||
if (array) {
|
||||
var result: T[] = [];
|
||||
for (var i = 0, len = array.length; i < len; i++) {
|
||||
var item = array[i];
|
||||
if (!contains(result, item)) result.push(item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function sum(array: any[], prop: string): number {
|
||||
var result = 0;
|
||||
for (var i = 0; i < array.length; i++) {
|
||||
|
|
|
@ -84,6 +84,7 @@ module ts {
|
|||
An_object_literal_cannot_have_property_and_accessor_with_the_same_name: { code: 1119, category: DiagnosticCategory.Error, key: "An object literal cannot have property and accessor with the same name." },
|
||||
An_export_assignment_cannot_have_modifiers: { code: 1120, category: DiagnosticCategory.Error, key: "An export assignment cannot have modifiers." },
|
||||
Octal_literals_are_not_allowed_in_strict_mode: { code: 1121, category: DiagnosticCategory.Error, key: "Octal literals are not allowed in strict mode." },
|
||||
A_tuple_type_element_list_cannot_be_empty: { code: 1122, category: DiagnosticCategory.Error, key: "A tuple type element list cannot be empty." },
|
||||
Variable_declaration_list_cannot_be_empty: { code: 1123, category: DiagnosticCategory.Error, key: "Variable declaration list cannot be empty." },
|
||||
Digit_expected: { code: 1124, category: DiagnosticCategory.Error, key: "Digit expected." },
|
||||
Hexadecimal_digit_expected: { code: 1125, category: DiagnosticCategory.Error, key: "Hexadecimal digit expected." },
|
||||
|
|
|
@ -327,6 +327,10 @@
|
|||
"category": "Error",
|
||||
"code": 1121
|
||||
},
|
||||
"A tuple type element list cannot be empty.": {
|
||||
"category": "Error",
|
||||
"code": 1122
|
||||
},
|
||||
"Variable declaration list cannot be empty.": {
|
||||
"category": "Error",
|
||||
"code": 1123
|
||||
|
|
|
@ -228,6 +228,8 @@ module ts {
|
|||
return children((<TypeLiteralNode>node).members);
|
||||
case SyntaxKind.ArrayType:
|
||||
return child((<ArrayTypeNode>node).elementType);
|
||||
case SyntaxKind.TupleType:
|
||||
return children((<TupleTypeNode>node).elementTypes);
|
||||
case SyntaxKind.ArrayLiteral:
|
||||
return children((<ArrayLiteral>node).elements);
|
||||
case SyntaxKind.ObjectLiteral:
|
||||
|
@ -520,6 +522,7 @@ module ts {
|
|||
Parameters, // Parameters in parameter list
|
||||
TypeParameters, // Type parameters in type parameter list
|
||||
TypeArguments, // Type arguments in type argument list
|
||||
TupleElementTypes, // Element types in tuple element type list
|
||||
Count // Number of parsing contexts
|
||||
}
|
||||
|
||||
|
@ -547,6 +550,7 @@ module ts {
|
|||
case ParsingContext.Parameters: return Diagnostics.Parameter_declaration_expected;
|
||||
case ParsingContext.TypeParameters: return Diagnostics.Type_parameter_declaration_expected;
|
||||
case ParsingContext.TypeArguments: return Diagnostics.Type_argument_expected;
|
||||
case ParsingContext.TupleElementTypes: return Diagnostics.Type_expected;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1015,6 +1019,7 @@ module ts {
|
|||
case ParsingContext.Parameters:
|
||||
return isParameter();
|
||||
case ParsingContext.TypeArguments:
|
||||
case ParsingContext.TupleElementTypes:
|
||||
return isType();
|
||||
}
|
||||
|
||||
|
@ -1050,6 +1055,7 @@ module ts {
|
|||
// Tokens other than ')' are here for better error recovery
|
||||
return token === SyntaxKind.CloseParenToken || token === SyntaxKind.SemicolonToken;
|
||||
case ParsingContext.ArrayLiteralMembers:
|
||||
case ParsingContext.TupleElementTypes:
|
||||
return token === SyntaxKind.CloseBracketToken;
|
||||
case ParsingContext.Parameters:
|
||||
// Tokens other than ')' and ']' (the latter for index signatures) are here for better error recovery
|
||||
|
@ -1570,6 +1576,17 @@ module ts {
|
|||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseTupleType(): TupleTypeNode {
|
||||
var node = <TupleTypeNode>createNode(SyntaxKind.TupleType);
|
||||
var startTokenPos = scanner.getTokenPos();
|
||||
var startErrorCount = file.syntacticErrors.length;
|
||||
node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
|
||||
if (!node.elementTypes.length && file.syntacticErrors.length === startErrorCount) {
|
||||
grammarErrorAtPos(startTokenPos, scanner.getStartPos() - startTokenPos, Diagnostics.A_tuple_type_element_list_cannot_be_empty);
|
||||
}
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseFunctionType(signatureKind: SyntaxKind): TypeLiteralNode {
|
||||
var node = <TypeLiteralNode>createNode(SyntaxKind.TypeLiteral);
|
||||
var member = <SignatureDeclaration>createNode(signatureKind);
|
||||
|
@ -1600,6 +1617,8 @@ module ts {
|
|||
return parseTypeQuery();
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
return parseTypeLiteral();
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
return parseTupleType();
|
||||
case SyntaxKind.OpenParenToken:
|
||||
case SyntaxKind.LessThanToken:
|
||||
return parseFunctionType(SyntaxKind.CallSignature);
|
||||
|
@ -1623,6 +1642,7 @@ module ts {
|
|||
case SyntaxKind.VoidKeyword:
|
||||
case SyntaxKind.TypeOfKeyword:
|
||||
case SyntaxKind.OpenBraceToken:
|
||||
case SyntaxKind.OpenBracketToken:
|
||||
case SyntaxKind.LessThanToken:
|
||||
case SyntaxKind.NewKeyword:
|
||||
return true;
|
||||
|
|
|
@ -149,6 +149,7 @@ module ts {
|
|||
TypeQuery,
|
||||
TypeLiteral,
|
||||
ArrayType,
|
||||
TupleType,
|
||||
// Expression
|
||||
ArrayLiteral,
|
||||
ObjectLiteral,
|
||||
|
@ -219,7 +220,7 @@ module ts {
|
|||
FirstFutureReservedWord = ImplementsKeyword,
|
||||
LastFutureReservedWord = YieldKeyword,
|
||||
FirstTypeNode = TypeReference,
|
||||
LastTypeNode = ArrayType,
|
||||
LastTypeNode = TupleType,
|
||||
FirstPunctuation = OpenBraceToken,
|
||||
LastPunctuation = CaretEqualsToken
|
||||
}
|
||||
|
@ -320,6 +321,10 @@ module ts {
|
|||
elementType: TypeNode;
|
||||
}
|
||||
|
||||
export interface TupleTypeNode extends TypeNode {
|
||||
elementTypes: NodeArray<TypeNode>;
|
||||
}
|
||||
|
||||
export interface StringLiteralTypeNode extends TypeNode {
|
||||
text: string;
|
||||
}
|
||||
|
@ -803,13 +808,14 @@ module ts {
|
|||
Class = 0x00000400, // Class
|
||||
Interface = 0x00000800, // Interface
|
||||
Reference = 0x00001000, // Generic type reference
|
||||
Anonymous = 0x00002000, // Anonymous
|
||||
FromSignature = 0x00004000, // Created for signature assignment check
|
||||
Tuple = 0x00002000, // Tuple
|
||||
Anonymous = 0x00004000, // Anonymous
|
||||
FromSignature = 0x00008000, // Created for signature assignment check
|
||||
|
||||
Intrinsic = Any | String | Number | Boolean | Void | Undefined | Null,
|
||||
StringLike = String | StringLiteral,
|
||||
NumberLike = Number | Enum,
|
||||
ObjectType = Class | Interface | Reference | Anonymous
|
||||
ObjectType = Class | Interface | Reference | Tuple | Anonymous
|
||||
}
|
||||
|
||||
// Properties common to all types
|
||||
|
@ -862,6 +868,11 @@ module ts {
|
|||
openReferenceChecks: Map<boolean>; // Open type reference check cache
|
||||
}
|
||||
|
||||
export interface TupleType extends ObjectType {
|
||||
elementTypes: Type[]; // Element types
|
||||
baseArrayType: TypeReference; // Array<T> where T is best common type of element types
|
||||
}
|
||||
|
||||
// Resolved object type
|
||||
export interface ResolvedObjectType extends ObjectType {
|
||||
members: SymbolTable; // Properties by name
|
||||
|
|
87
tests/baselines/reference/tupleTypes.errors.txt
Normal file
87
tests/baselines/reference/tupleTypes.errors.txt
Normal file
|
@ -0,0 +1,87 @@
|
|||
==== tests/cases/compiler/tupleTypes.ts (9 errors) ====
|
||||
var v1: []; // Error
|
||||
~~
|
||||
!!! A tuple type element list cannot be empty.
|
||||
var v2: [number];
|
||||
var v3: [number, string];
|
||||
var v4: [number, [string, string]];
|
||||
|
||||
var t: [number, string];
|
||||
var t0 = t[0]; // number
|
||||
var t0: number;
|
||||
var t1 = t[1]; // string
|
||||
var t1: string;
|
||||
var t2 = t[2]; // {}
|
||||
var t2: {};
|
||||
|
||||
t = []; // Error
|
||||
~
|
||||
!!! Type '{}[]' is not assignable to type '[number, string]':
|
||||
!!! Property '0' is missing in type '{}[]'.
|
||||
t = [1]; // Error
|
||||
~
|
||||
!!! Type '[number]' is not assignable to type '[number, string]':
|
||||
!!! Property '1' is missing in type '[number]'.
|
||||
t = [1, "hello"]; // Ok
|
||||
t = ["hello", 1]; // Error
|
||||
~
|
||||
!!! Type '[string, number]' is not assignable to type '[number, string]':
|
||||
!!! Types of property '0' are incompatible:
|
||||
!!! Type 'string' is not assignable to type 'number'.
|
||||
t = [1, "hello", 2]; // Ok
|
||||
|
||||
var tf: [string, (x: string) => number] = ["hello", x => x.length];
|
||||
|
||||
declare function ff<T, U>(a: T, b: [T, (x: T) => U]): U;
|
||||
var ff1 = ff("hello", ["foo", x => x.length]);
|
||||
var ff1: number;
|
||||
|
||||
function tuple2<T0, T1>(item0: T0, item1: T1): [T0, T1]{
|
||||
return [item0, item1];
|
||||
}
|
||||
|
||||
var tt = tuple2(1, "string");
|
||||
var tt0 = tt[0];
|
||||
var tt0: number;
|
||||
var tt1 = tt[1];
|
||||
var tt1: string;
|
||||
var tt2 = tt[2];
|
||||
var tt2: {};
|
||||
|
||||
tt = tuple2(1, undefined);
|
||||
tt = [1, undefined];
|
||||
tt = [undefined, undefined];
|
||||
tt = []; // Error
|
||||
~~
|
||||
!!! Type '{}[]' is not assignable to type '[number, string]'.
|
||||
|
||||
var a: number[];
|
||||
var a1: [number, string];
|
||||
var a2: [number, number];
|
||||
var a3: [number, {}];
|
||||
a = a1; // Error
|
||||
~
|
||||
!!! Type '[number, string]' is not assignable to type 'number[]':
|
||||
!!! Types of property 'pop' are incompatible:
|
||||
!!! Type '() => {}' is not assignable to type '() => number':
|
||||
!!! Type '{}' is not assignable to type 'number'.
|
||||
a = a2;
|
||||
a = a3; // Error
|
||||
~
|
||||
!!! Type '[number, {}]' is not assignable to type 'number[]':
|
||||
!!! Types of property 'pop' are incompatible:
|
||||
!!! Type '() => {}' is not assignable to type '() => number':
|
||||
!!! Type '{}' is not assignable to type 'number'.
|
||||
a1 = a2; // Error
|
||||
~~
|
||||
!!! Type '[number, number]' is not assignable to type '[number, string]':
|
||||
!!! Types of property '1' are incompatible:
|
||||
!!! Type 'number' is not assignable to type 'string'.
|
||||
a1 = a3; // Error
|
||||
~~
|
||||
!!! Type '[number, {}]' is not assignable to type '[number, string]':
|
||||
!!! Types of property '1' are incompatible:
|
||||
!!! Type '{}' is not assignable to type 'string'.
|
||||
a3 = a1;
|
||||
a3 = a2;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
==== tests/cases/compiler/typeName1.ts (16 errors) ====
|
||||
==== tests/cases/compiler/typeName1.ts (17 errors) ====
|
||||
interface I {
|
||||
k;
|
||||
}
|
||||
|
@ -55,6 +55,8 @@
|
|||
~~~
|
||||
!!! Type 'number' is not assignable to type '{ z: I; x: boolean; y: (s: string) => boolean; w: { (): boolean; [x: string]: { x: any; y: any; }; [x: number]: { x: any; y: any; }; z: I; }; }[][]':
|
||||
!!! Property 'length' is missing in type 'Number'.
|
||||
~~~~
|
||||
!!! Property 'z' of type 'I' is not assignable to string index type '{ x: any; y: any; }'.
|
||||
var x13:{ new(): number; new(n:number):number; x: string; w: {y: number;}; (): {}; } = 3;
|
||||
~~~
|
||||
!!! Type 'number' is not assignable to type '{ (): {}; new (): number; new (n: number): number; x: string; w: { y: number; }; }':
|
||||
|
|
53
tests/cases/compiler/tupleTypes.ts
Normal file
53
tests/cases/compiler/tupleTypes.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
var v1: []; // Error
|
||||
var v2: [number];
|
||||
var v3: [number, string];
|
||||
var v4: [number, [string, string]];
|
||||
|
||||
var t: [number, string];
|
||||
var t0 = t[0]; // number
|
||||
var t0: number;
|
||||
var t1 = t[1]; // string
|
||||
var t1: string;
|
||||
var t2 = t[2]; // {}
|
||||
var t2: {};
|
||||
|
||||
t = []; // Error
|
||||
t = [1]; // Error
|
||||
t = [1, "hello"]; // Ok
|
||||
t = ["hello", 1]; // Error
|
||||
t = [1, "hello", 2]; // Ok
|
||||
|
||||
var tf: [string, (x: string) => number] = ["hello", x => x.length];
|
||||
|
||||
declare function ff<T, U>(a: T, b: [T, (x: T) => U]): U;
|
||||
var ff1 = ff("hello", ["foo", x => x.length]);
|
||||
var ff1: number;
|
||||
|
||||
function tuple2<T0, T1>(item0: T0, item1: T1): [T0, T1]{
|
||||
return [item0, item1];
|
||||
}
|
||||
|
||||
var tt = tuple2(1, "string");
|
||||
var tt0 = tt[0];
|
||||
var tt0: number;
|
||||
var tt1 = tt[1];
|
||||
var tt1: string;
|
||||
var tt2 = tt[2];
|
||||
var tt2: {};
|
||||
|
||||
tt = tuple2(1, undefined);
|
||||
tt = [1, undefined];
|
||||
tt = [undefined, undefined];
|
||||
tt = []; // Error
|
||||
|
||||
var a: number[];
|
||||
var a1: [number, string];
|
||||
var a2: [number, number];
|
||||
var a3: [number, {}];
|
||||
a = a1; // Error
|
||||
a = a2;
|
||||
a = a3; // Error
|
||||
a1 = a2; // Error
|
||||
a1 = a3; // Error
|
||||
a3 = a1;
|
||||
a3 = a2;
|
Loading…
Reference in a new issue