|
|
|
|
@ -41,6 +41,9 @@ module ts {
|
|
|
|
|
var anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
|
|
|
|
var noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
|
|
|
|
|
|
|
|
|
var anySignature = createSignature(undefined, undefined, emptyArray, anyType, 0, false, false);
|
|
|
|
|
var unknownSignature = createSignature(undefined, undefined, emptyArray, unknownType, 0, false, false);
|
|
|
|
|
|
|
|
|
|
var globals: SymbolTable = {};
|
|
|
|
|
|
|
|
|
|
var globalObjectType: ObjectType;
|
|
|
|
|
@ -53,6 +56,7 @@ module ts {
|
|
|
|
|
|
|
|
|
|
var stringLiteralTypes: Map<StringLiteralType> = {};
|
|
|
|
|
|
|
|
|
|
var fullTypeCheck = false;
|
|
|
|
|
var emitExtends = false;
|
|
|
|
|
|
|
|
|
|
var mergedSymbols: Symbol[] = [];
|
|
|
|
|
@ -327,7 +331,7 @@ module ts {
|
|
|
|
|
case SyntaxKind.CatchBlock:
|
|
|
|
|
var id = (<CatchBlock>location).variable;
|
|
|
|
|
if (name === id.text) {
|
|
|
|
|
return returnResolvedSymbol((<CatchBlock>location).variable.symbol);
|
|
|
|
|
return returnResolvedSymbol(location.symbol);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
@ -1104,129 +1108,99 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getTypeOfVariableDeclaration(declaration: VariableDeclaration): Type {
|
|
|
|
|
var type: Type;
|
|
|
|
|
|
|
|
|
|
if (declaration.parent.kind === SyntaxKind.CatchBlock || declaration.parent.kind === SyntaxKind.ForInStatement) {
|
|
|
|
|
type = anyType;
|
|
|
|
|
// A variable declared in a for..in statement is always of type any
|
|
|
|
|
if (declaration.parent.kind === SyntaxKind.ForInStatement) {
|
|
|
|
|
return anyType;
|
|
|
|
|
}
|
|
|
|
|
else if (declaration.type) {
|
|
|
|
|
type = getTypeFromTypeNode(declaration.type);
|
|
|
|
|
// Use type from type annotation if one is present
|
|
|
|
|
if (declaration.type) {
|
|
|
|
|
return getTypeFromTypeNode(declaration.type);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// TypeScript 1.0 spec (April 2014):
|
|
|
|
|
// If only one accessor includes a type annotation, the other behaves as if it had the same type annotation.
|
|
|
|
|
// If neither accessor includes a type annotation, the inferred return type of the get accessor becomes the parameter type of the set accessor.
|
|
|
|
|
if (declaration.kind === SyntaxKind.Parameter && declaration.parent.kind === SyntaxKind.SetAccessor) {
|
|
|
|
|
if (declaration.kind === SyntaxKind.Parameter) {
|
|
|
|
|
var func = <FunctionDeclaration>declaration.parent;
|
|
|
|
|
// For a parameter of a set accessor, use the type of the get accessor if one is present
|
|
|
|
|
if (func.kind === SyntaxKind.SetAccessor) {
|
|
|
|
|
var getter = <AccessorDeclaration>getDeclarationOfKind(declaration.parent.symbol, SyntaxKind.GetAccessor);
|
|
|
|
|
if (getter) {
|
|
|
|
|
//getReturnTypeOfSignature will check both type annotation and return type inferred from body
|
|
|
|
|
type = getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
|
|
|
|
|
return getReturnTypeOfSignature(getSignatureFromDeclaration(getter));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var unwidenedType: Type;
|
|
|
|
|
|
|
|
|
|
if (!type) {
|
|
|
|
|
if (declaration.initializer) {
|
|
|
|
|
unwidenedType = checkAndMarkExpression(declaration.initializer);
|
|
|
|
|
type = getWidenedType(unwidenedType);
|
|
|
|
|
}
|
|
|
|
|
else if (declaration.flags & NodeFlags.Rest) {
|
|
|
|
|
type = createArrayType(anyType);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
type = anyType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (program.getCompilerOptions().noImplicitAny && shouldReportNoImplicitAnyOnVariableOrParameterOrProperty(declaration, type, unwidenedType)) {
|
|
|
|
|
reportNoImplicitAnyOnVariableOrParameterOrProperty(declaration, type);
|
|
|
|
|
// Use contextual parameter type if one is available
|
|
|
|
|
var type = getContextuallyTypedParameterType(declaration);
|
|
|
|
|
if (type) {
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Use the type of the initializer expression if one is present
|
|
|
|
|
if (declaration.initializer) {
|
|
|
|
|
var unwidenedType = checkAndMarkExpression(declaration.initializer);
|
|
|
|
|
var type = getWidenedType(unwidenedType);
|
|
|
|
|
if (type !== unwidenedType) {
|
|
|
|
|
checkImplicitAny(type);
|
|
|
|
|
}
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
// Rest parameters default to type any[], other parameters default to type any
|
|
|
|
|
var type = declaration.flags & NodeFlags.Rest ? createArrayType(anyType) : anyType;
|
|
|
|
|
checkImplicitAny(type);
|
|
|
|
|
return type;
|
|
|
|
|
|
|
|
|
|
function shouldReportNoImplicitAnyOnVariableOrParameterOrProperty(declaration: VariableDeclaration, type: Type, unwidenedType: Type): boolean {
|
|
|
|
|
// If we attempted to widen, the resulting type has to be a different.
|
|
|
|
|
if (type === unwidenedType) {
|
|
|
|
|
return false;
|
|
|
|
|
function checkImplicitAny(type: Type) {
|
|
|
|
|
if (!program.getCompilerOptions().noImplicitAny) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We need to have ended up with 'any', 'any[]', 'any[][]', etc.
|
|
|
|
|
if (getInnermostTypeOfNestedArrayTypes(type) !== anyType) {
|
|
|
|
|
return false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ignore privates within ambient contexts; they exist purely for documentative purposes to avoid name clashing.
|
|
|
|
|
// (e.g. privates within .d.ts files do not expose type information)
|
|
|
|
|
if (isPrivateWithinAmbient(declaration) || (declaration.kind === SyntaxKind.Parameter && isPrivateWithinAmbient(declaration.parent))) {
|
|
|
|
|
return false;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function reportNoImplicitAnyOnVariableOrParameterOrProperty(declaration: VariableDeclaration, type: Type): void {
|
|
|
|
|
var varName = identifierToString(declaration.name);
|
|
|
|
|
var typeName = typeToString(type);
|
|
|
|
|
|
|
|
|
|
switch (declaration.kind) {
|
|
|
|
|
case SyntaxKind.VariableDeclaration:
|
|
|
|
|
error(declaration, Diagnostics.Variable_0_implicitly_has_an_1_type, varName, typeName)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SyntaxKind.Property:
|
|
|
|
|
error(declaration, Diagnostics.Member_0_implicitly_has_an_1_type, varName, typeName)
|
|
|
|
|
var diagnostic = Diagnostics.Member_0_implicitly_has_an_1_type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SyntaxKind.Parameter:
|
|
|
|
|
var funcDeclaration = <FunctionDeclaration>declaration.parent;
|
|
|
|
|
|
|
|
|
|
// If this is a rest parameter, we should have widened specifically to 'any[]'.
|
|
|
|
|
if (declaration.flags & NodeFlags.Rest) {
|
|
|
|
|
error(declaration, Diagnostics.Rest_parameter_0_implicitly_has_an_any_type, varName)
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
error(declaration, Diagnostics.Parameter_0_implicitly_has_an_1_type, varName, typeName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var diagnostic = declaration.flags & NodeFlags.Rest ?
|
|
|
|
|
Diagnostics.Rest_parameter_0_implicitly_has_an_any_type :
|
|
|
|
|
Diagnostics.Parameter_0_implicitly_has_an_1_type;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Debug.fail("Received a '" + SyntaxKind[declaration.kind] + "', but expected '" +
|
|
|
|
|
SyntaxKind[SyntaxKind.VariableDeclaration] + "', '" +
|
|
|
|
|
SyntaxKind[SyntaxKind.Property] + "', or '" +
|
|
|
|
|
SyntaxKind[SyntaxKind.Parameter] + "'.\r\n");
|
|
|
|
|
var diagnostic = Diagnostics.Variable_0_implicitly_has_an_1_type;
|
|
|
|
|
}
|
|
|
|
|
error(declaration, diagnostic, identifierToString(declaration.name), typeToString(type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
|
|
|
|
|
var links = getSymbolLinks(symbol);
|
|
|
|
|
if (!links.type) {
|
|
|
|
|
// Handle prototype property
|
|
|
|
|
if (symbol.flags & SymbolFlags.Prototype) {
|
|
|
|
|
links.type = getTypeOfPrototypeProperty(symbol);
|
|
|
|
|
return links.type = getTypeOfPrototypeProperty(symbol);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
links.type = resolvingType;
|
|
|
|
|
var type = getTypeOfVariableDeclaration(<VariableDeclaration>symbol.valueDeclaration);
|
|
|
|
|
if (links.type === resolvingType) {
|
|
|
|
|
links.type = type;
|
|
|
|
|
}
|
|
|
|
|
// Handle catch clause variables
|
|
|
|
|
var declaration = symbol.valueDeclaration;
|
|
|
|
|
if (declaration.kind === SyntaxKind.CatchBlock) {
|
|
|
|
|
return links.type = anyType;
|
|
|
|
|
}
|
|
|
|
|
// Handle variable, parameter or property
|
|
|
|
|
links.type = resolvingType;
|
|
|
|
|
var type = getTypeOfVariableDeclaration(<VariableDeclaration>declaration);
|
|
|
|
|
if (links.type === resolvingType) {
|
|
|
|
|
links.type = type;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (links.type === resolvingType) {
|
|
|
|
|
links.type = anyType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return links.type;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSetAccessorTypeAnnotationNode(accessor: AccessorDeclaration): TypeNode {
|
|
|
|
|
return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type;
|
|
|
|
|
return accessor && accessor.parameters.length > 0 && accessor.parameters[0].type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getAnnotatedAccessorType(accessor: AccessorDeclaration): Type {
|
|
|
|
|
@ -2296,15 +2270,17 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function instantiateType(type: Type, mapper: TypeMapper): Type {
|
|
|
|
|
if (type.flags & TypeFlags.TypeParameter) {
|
|
|
|
|
return mapper(type);
|
|
|
|
|
}
|
|
|
|
|
if (type.flags & TypeFlags.Anonymous) {
|
|
|
|
|
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ?
|
|
|
|
|
instantiateAnonymousType(<ObjectType>type, mapper) : type;
|
|
|
|
|
}
|
|
|
|
|
if (type.flags & TypeFlags.Reference) {
|
|
|
|
|
return createTypeReference((<TypeReference>type).target, instantiateList((<TypeReference>type).typeArguments, mapper, instantiateType));
|
|
|
|
|
if (mapper !== identityMapper) {
|
|
|
|
|
if (type.flags & TypeFlags.TypeParameter) {
|
|
|
|
|
return mapper(type);
|
|
|
|
|
}
|
|
|
|
|
if (type.flags & TypeFlags.Anonymous) {
|
|
|
|
|
return type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) ?
|
|
|
|
|
instantiateAnonymousType(<ObjectType>type, mapper) : type;
|
|
|
|
|
}
|
|
|
|
|
if (type.flags & TypeFlags.Reference) {
|
|
|
|
|
return createTypeReference((<TypeReference>type).target, instantiateList((<TypeReference>type).typeArguments, mapper, instantiateType));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
@ -3461,22 +3437,171 @@ module ts {
|
|
|
|
|
return unknownType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getTypeOfExpression(node: Expression): Type {
|
|
|
|
|
// TODO: Optimize by caching type in NodeLinks?
|
|
|
|
|
return checkExpression(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return contextual type of parameter or undefined if no contextual type is available
|
|
|
|
|
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type {
|
|
|
|
|
var func = <FunctionDeclaration>parameter.parent;
|
|
|
|
|
if (func.kind === SyntaxKind.FunctionExpression || func.kind === SyntaxKind.ArrowFunction) {
|
|
|
|
|
if (isContextSensitiveExpression(func)) {
|
|
|
|
|
var signature = getContextualSignature(func);
|
|
|
|
|
if (signature) {
|
|
|
|
|
return getTypeAtPosition(signature, indexOf(func.parameters, parameter));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForInitializerExpression(node: Expression): Type {
|
|
|
|
|
var declaration = <VariableDeclaration>node.parent;
|
|
|
|
|
if (node === declaration.initializer) {
|
|
|
|
|
if (declaration.type) {
|
|
|
|
|
return getTypeFromTypeNode(declaration.type);
|
|
|
|
|
}
|
|
|
|
|
if (declaration.kind === SyntaxKind.Parameter) {
|
|
|
|
|
return getContextuallyTypedParameterType(declaration);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForReturnExpression(node: Expression): Type {
|
|
|
|
|
var func = getContainingFunction(node);
|
|
|
|
|
if (func) {
|
|
|
|
|
// If the containing function has a return type annotation, is a constructor, or is a get accessor whose
|
|
|
|
|
// corresponding set accessor has a type annotation, return statements in the function are contextually typed
|
|
|
|
|
if (func.type || func.kind === SyntaxKind.Constructor || func.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(<AccessorDeclaration>getDeclarationOfKind(func.symbol, SyntaxKind.SetAccessor))) {
|
|
|
|
|
return getReturnTypeOfSignature(getSignatureFromDeclaration(func));
|
|
|
|
|
}
|
|
|
|
|
// Otherwise, if the containing function is contextually typed by a function type with exactly one call signature
|
|
|
|
|
// and that call signature is non-generic, return statements are contextually typed by the return type of the signature
|
|
|
|
|
var signature = getContextualSignature(func);
|
|
|
|
|
if (signature) {
|
|
|
|
|
return getReturnTypeOfSignature(signature);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForArgument(node: Expression): Type {
|
|
|
|
|
var callExpression = <CallExpression>node.parent;
|
|
|
|
|
var argIndex = indexOf(callExpression.arguments, node);
|
|
|
|
|
if (argIndex >= 0) {
|
|
|
|
|
var signature = getResolvedSignature(callExpression);
|
|
|
|
|
return getTypeAtPosition(signature, argIndex);
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForBinaryOperand(node: Expression): Type {
|
|
|
|
|
var binaryExpression = <BinaryExpression>node.parent;
|
|
|
|
|
var operator = binaryExpression.operator;
|
|
|
|
|
if (operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment) {
|
|
|
|
|
if (node === binaryExpression.right) {
|
|
|
|
|
return getTypeOfExpression(binaryExpression.left);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (operator === SyntaxKind.BarBarToken) {
|
|
|
|
|
var type = getContextualType(binaryExpression);
|
|
|
|
|
if (!type && node === binaryExpression.right) {
|
|
|
|
|
type = getTypeOfExpression(binaryExpression.left);
|
|
|
|
|
}
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForPropertyExpression(node: Expression): Type {
|
|
|
|
|
var declaration = <PropertyDeclaration>node.parent;
|
|
|
|
|
var objectLiteral = <ObjectLiteral>declaration.parent;
|
|
|
|
|
var type = getContextualType(objectLiteral);
|
|
|
|
|
var name = declaration.name.text;
|
|
|
|
|
if (type && name) {
|
|
|
|
|
var prop = getPropertyOfType(type, name);
|
|
|
|
|
if (prop) {
|
|
|
|
|
return getTypeOfSymbol(prop);
|
|
|
|
|
}
|
|
|
|
|
return isNumericName(name) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String);
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForElementExpression(node: Expression): Type {
|
|
|
|
|
var arrayLiteral = <ArrayLiteral>node.parent;
|
|
|
|
|
var type = getContextualType(arrayLiteral);
|
|
|
|
|
return type ? getIndexTypeOfType(type, IndexKind.Number) : undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForConditionalOperand(node: Expression): Type {
|
|
|
|
|
var conditional = <ConditionalExpression>node.parent;
|
|
|
|
|
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualType(node: Expression): Type {
|
|
|
|
|
if (node.contextualType) {
|
|
|
|
|
return node.contextualType;
|
|
|
|
|
}
|
|
|
|
|
var parent = node.parent;
|
|
|
|
|
switch (parent.kind) {
|
|
|
|
|
case SyntaxKind.VariableDeclaration:
|
|
|
|
|
case SyntaxKind.Parameter:
|
|
|
|
|
case SyntaxKind.Property:
|
|
|
|
|
return getContextualTypeForInitializerExpression(node);
|
|
|
|
|
case SyntaxKind.ArrowFunction:
|
|
|
|
|
case SyntaxKind.ReturnStatement:
|
|
|
|
|
return getContextualTypeForReturnExpression(node);
|
|
|
|
|
case SyntaxKind.CallExpression:
|
|
|
|
|
case SyntaxKind.NewExpression:
|
|
|
|
|
return getContextualTypeForArgument(node);
|
|
|
|
|
case SyntaxKind.TypeAssertion:
|
|
|
|
|
return getTypeFromTypeNode((<TypeAssertion>parent).type);
|
|
|
|
|
case SyntaxKind.BinaryExpression:
|
|
|
|
|
return getContextualTypeForBinaryOperand(node);
|
|
|
|
|
case SyntaxKind.PropertyAssignment:
|
|
|
|
|
return getContextualTypeForPropertyExpression(node);
|
|
|
|
|
case SyntaxKind.ArrayLiteral:
|
|
|
|
|
return getContextualTypeForElementExpression(node);
|
|
|
|
|
case SyntaxKind.ConditionalExpression:
|
|
|
|
|
return getContextualTypeForConditionalOperand(node);
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualSignature(node: Expression): Signature {
|
|
|
|
|
var type = getContextualType(node);
|
|
|
|
|
if (type) {
|
|
|
|
|
var signatures = getSignaturesOfType(type, SignatureKind.Call);
|
|
|
|
|
if (signatures.length === 1) {
|
|
|
|
|
var signature = signatures[0];
|
|
|
|
|
if (!signature.typeParameters) {
|
|
|
|
|
return signature;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Presence of a contextual type mapper indicates inferential typing, except the identityMapper object is
|
|
|
|
|
// used as a special marker for other purposes.
|
|
|
|
|
function isInferentialContext(mapper: TypeMapper) {
|
|
|
|
|
return mapper && mapper !== identityMapper;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkArrayLiteral(node: ArrayLiteral, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
var contextualElementType = contextualType && getIndexTypeOfType(contextualType, IndexKind.Number);
|
|
|
|
|
function checkArrayLiteral(node: ArrayLiteral, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
var elementTypes: Type[] = [];
|
|
|
|
|
forEach(node.elements, element => {
|
|
|
|
|
if (element.kind !== SyntaxKind.OmittedExpression) {
|
|
|
|
|
var type = checkExpression(element, contextualElementType, contextualMapper);
|
|
|
|
|
var type = checkExpression(element, contextualMapper);
|
|
|
|
|
if (!contains(elementTypes, type)) elementTypes.push(type);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
var elementType = getBestCommonType(elementTypes, isInferentialContext(contextualMapper) ? undefined : contextualElementType, 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;
|
|
|
|
|
return createArrayType(elementType);
|
|
|
|
|
}
|
|
|
|
|
@ -3485,22 +3610,16 @@ module ts {
|
|
|
|
|
return !isNaN(<number><any>name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualTypeForProperty(type: Type, name: string) {
|
|
|
|
|
var prop = getPropertyOfType(type, name);
|
|
|
|
|
if (prop) return getTypeOfSymbol(prop);
|
|
|
|
|
return isNumericName(name) && getIndexTypeOfType(type, IndexKind.Number) || getIndexTypeOfType(type, IndexKind.String);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkObjectLiteral(node: ObjectLiteral, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
function checkObjectLiteral(node: ObjectLiteral, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
var members = node.symbol.members;
|
|
|
|
|
var properties: SymbolTable = {};
|
|
|
|
|
var contextualType = getContextualType(node);
|
|
|
|
|
|
|
|
|
|
for (var id in members) {
|
|
|
|
|
if (hasProperty(members, id)) {
|
|
|
|
|
var member = members[id];
|
|
|
|
|
if (member.flags & SymbolFlags.Property) {
|
|
|
|
|
var contextualPropType = contextualType && getContextualTypeForProperty(contextualType, member.name);
|
|
|
|
|
var type = checkExpression((<PropertyDeclaration>member.declarations[0]).initializer, contextualPropType, contextualMapper);
|
|
|
|
|
var type = checkExpression((<PropertyDeclaration>member.declarations[0]).initializer, contextualMapper);
|
|
|
|
|
var prop = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient, member.name);
|
|
|
|
|
prop.declarations = member.declarations;
|
|
|
|
|
prop.parent = member.parent;
|
|
|
|
|
@ -3527,11 +3646,11 @@ module ts {
|
|
|
|
|
properties[member.name] = member;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var stringIndexType = getIndexType(properties, IndexKind.String);
|
|
|
|
|
var numberIndexType = getIndexType(properties, IndexKind.Number);
|
|
|
|
|
var stringIndexType = getIndexType(IndexKind.String);
|
|
|
|
|
var numberIndexType = getIndexType(IndexKind.Number);
|
|
|
|
|
return createAnonymousType(node.symbol, properties, emptyArray, emptyArray, stringIndexType, numberIndexType);
|
|
|
|
|
|
|
|
|
|
function getIndexType(properties: SymbolTable, kind: IndexKind) {
|
|
|
|
|
function getIndexType(kind: IndexKind) {
|
|
|
|
|
if (contextualType) {
|
|
|
|
|
var indexType = getIndexTypeOfType(contextualType, kind);
|
|
|
|
|
if (indexType) {
|
|
|
|
|
@ -3544,7 +3663,6 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return getBestCommonType(propTypes, isInferentialContext(contextualMapper) ? undefined : indexType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -3659,14 +3777,16 @@ module ts {
|
|
|
|
|
return unknownType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkUntypedCall(node: CallExpression): Type {
|
|
|
|
|
forEach(node.arguments, argument => { checkExpression(argument); });
|
|
|
|
|
return anyType;
|
|
|
|
|
function resolveUntypedCall(node: CallExpression): Signature {
|
|
|
|
|
forEach(node.arguments, argument => {
|
|
|
|
|
checkExpression(argument);
|
|
|
|
|
});
|
|
|
|
|
return anySignature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkErrorCall(node: CallExpression): Type {
|
|
|
|
|
checkUntypedCall(node);
|
|
|
|
|
return unknownType;
|
|
|
|
|
function resolveErrorCall(node: CallExpression): Signature {
|
|
|
|
|
resolveUntypedCall(node);
|
|
|
|
|
return unknownSignature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isCandidateSignature(node: CallExpression, signature: Signature) {
|
|
|
|
|
@ -3725,7 +3845,7 @@ module ts {
|
|
|
|
|
|
|
|
|
|
// Inferentially type an expression by a contextual parameter type (section 4.12.2 in TypeScript spec)
|
|
|
|
|
function inferentiallyTypeExpession(expr: Expression, contextualType: Type, contextualMapper: TypeMapper): Type {
|
|
|
|
|
var type = checkExpression(expr, contextualType, contextualMapper);
|
|
|
|
|
var type = checkExpressionWithContextualType(expr, contextualType, contextualMapper);
|
|
|
|
|
var signature = getSingleCallSignature(type);
|
|
|
|
|
if (signature && signature.typeParameters) {
|
|
|
|
|
var contextualSignature = getSingleCallSignature(contextualType);
|
|
|
|
|
@ -3782,7 +3902,7 @@ module ts {
|
|
|
|
|
// String literals get string literal types unless we're reporting errors
|
|
|
|
|
var argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors ?
|
|
|
|
|
getStringLiteralType(<LiteralExpression>arg) :
|
|
|
|
|
checkExpression(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
|
|
|
|
checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
|
|
|
|
// Use argument expression as error location when reporting errors
|
|
|
|
|
var isValidArgument = checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
|
|
|
|
|
Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1,
|
|
|
|
|
@ -3795,12 +3915,12 @@ module ts {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkCall(node: CallExpression, signatures: Signature[]): Type {
|
|
|
|
|
function resolveCall(node: CallExpression, signatures: Signature[]): Signature {
|
|
|
|
|
forEach(node.typeArguments, checkSourceElement);
|
|
|
|
|
var candidates = collectCandidates(node, signatures);
|
|
|
|
|
if (!candidates.length) {
|
|
|
|
|
error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target);
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
var args = node.arguments || emptyArray;
|
|
|
|
|
var excludeArgument: boolean[];
|
|
|
|
|
@ -3826,7 +3946,7 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
var index = excludeArgument ? indexOf(excludeArgument, true) : -1;
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
return getReturnTypeOfSignature(candidate);
|
|
|
|
|
return candidate;
|
|
|
|
|
}
|
|
|
|
|
excludeArgument[index] = false;
|
|
|
|
|
}
|
|
|
|
|
@ -3839,35 +3959,29 @@ module ts {
|
|
|
|
|
// No signatures were applicable. Now report errors based on the last applicable signature with
|
|
|
|
|
// no arguments excluded from assignability checks.
|
|
|
|
|
checkApplicableSignature(node, candidate, relation, undefined, /*reportErrors*/ true);
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkCallExpression(node: CallExpression): Type {
|
|
|
|
|
function resolveCallExpression(node: CallExpression): Signature {
|
|
|
|
|
if (node.func.kind === SyntaxKind.SuperKeyword) {
|
|
|
|
|
var superType = checkSuperExpression(node.func, true);
|
|
|
|
|
if (superType !== unknownType) {
|
|
|
|
|
checkCall(node, getSignaturesOfType(superType, SignatureKind.Construct));
|
|
|
|
|
return resolveCall(node, getSignaturesOfType(superType, SignatureKind.Construct));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
checkUntypedCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TS 1.0 spec: 4.8.1
|
|
|
|
|
// The type of a super call expression is Void.
|
|
|
|
|
return voidType;
|
|
|
|
|
return resolveUntypedCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var funcType = checkExpression(node.func);
|
|
|
|
|
if (funcType === unknownType) {
|
|
|
|
|
// Another error has already been reported
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var apparentType = getApparentType(funcType)
|
|
|
|
|
if (<Type>apparentType === unknownType) {
|
|
|
|
|
// handler cases when funcType is type parameter with invalid constraint
|
|
|
|
|
// Another error was already reported
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Technically, this signatures list may be incomplete. We are taking the apparent type,
|
|
|
|
|
@ -3886,7 +4000,7 @@ module ts {
|
|
|
|
|
if (node.typeArguments) {
|
|
|
|
|
error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments);
|
|
|
|
|
}
|
|
|
|
|
return checkUntypedCall(node);
|
|
|
|
|
return resolveUntypedCall(node);
|
|
|
|
|
}
|
|
|
|
|
// If FuncExpr's apparent type(section 3.8.1) is a function type, the call is a typed function call.
|
|
|
|
|
// TypeScript employs overload resolution in typed function calls in order to support functions
|
|
|
|
|
@ -3898,16 +4012,16 @@ module ts {
|
|
|
|
|
else {
|
|
|
|
|
error(node, Diagnostics.Cannot_invoke_an_expression_whose_type_lacks_a_call_signature);
|
|
|
|
|
}
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
return checkCall(node, callSignatures);
|
|
|
|
|
return resolveCall(node, callSignatures);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkNewExpression(node: NewExpression): Type {
|
|
|
|
|
function resolveNewExpression(node: NewExpression): Signature {
|
|
|
|
|
var expressionType = checkExpression(node.func);
|
|
|
|
|
if (expressionType === unknownType) {
|
|
|
|
|
// Another error has already been reported
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
// TS 1.0 spec: 4.11
|
|
|
|
|
// If ConstructExpr is of type Any, Args can be any argument
|
|
|
|
|
@ -3917,7 +4031,7 @@ module ts {
|
|
|
|
|
error(node, Diagnostics.Untyped_function_calls_may_not_accept_type_arguments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return checkUntypedCall(node);
|
|
|
|
|
return resolveUntypedCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If ConstructExpr's apparent type(section 3.8.1) is an object type with one or
|
|
|
|
|
@ -3929,7 +4043,7 @@ module ts {
|
|
|
|
|
if (<Type>expressionType === unknownType) {
|
|
|
|
|
// handler cases when original expressionType is a type parameter with invalid constraint
|
|
|
|
|
// another error has already been reported
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Technically, this signatures list may be incomplete. We are taking the apparent type,
|
|
|
|
|
@ -3938,7 +4052,7 @@ module ts {
|
|
|
|
|
// that the user will not add any.
|
|
|
|
|
var constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct);
|
|
|
|
|
if (constructSignatures.length) {
|
|
|
|
|
return checkCall(node, constructSignatures);
|
|
|
|
|
return resolveCall(node, constructSignatures);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If ConstructExpr's apparent type is an object type with no construct signatures but
|
|
|
|
|
@ -3947,45 +4061,54 @@ module ts {
|
|
|
|
|
// operation is Any.
|
|
|
|
|
var callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
|
|
|
|
|
if (callSignatures.length) {
|
|
|
|
|
var type = checkCall(node, callSignatures);
|
|
|
|
|
|
|
|
|
|
if (type !== voidType) {
|
|
|
|
|
var signature = resolveCall(node, callSignatures);
|
|
|
|
|
if (getReturnTypeOfSignature(signature) !== voidType) {
|
|
|
|
|
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Since we found no constructor signature, we (implicitly) return any.
|
|
|
|
|
if (program.getCompilerOptions().noImplicitAny) {
|
|
|
|
|
error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return anyType;
|
|
|
|
|
return signature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
error(node, Diagnostics.Cannot_use_new_with_an_expression_whose_type_lacks_a_call_or_construct_signature);
|
|
|
|
|
return checkErrorCall(node);
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getResolvedSignature(node: CallExpression): Signature {
|
|
|
|
|
var links = getNodeLinks(node);
|
|
|
|
|
if (!links.resolvedSignature) {
|
|
|
|
|
links.resolvedSignature = anySignature;
|
|
|
|
|
links.resolvedSignature = node.kind === SyntaxKind.CallExpression ? resolveCallExpression(node) : resolveNewExpression(node);
|
|
|
|
|
}
|
|
|
|
|
return links.resolvedSignature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkCallExpression(node: CallExpression): Type {
|
|
|
|
|
var signature = getResolvedSignature(node);
|
|
|
|
|
if (node.func.kind === SyntaxKind.SuperKeyword) {
|
|
|
|
|
return voidType;
|
|
|
|
|
}
|
|
|
|
|
if (node.kind === SyntaxKind.NewExpression) {
|
|
|
|
|
var declaration = signature.declaration;
|
|
|
|
|
if (declaration && (declaration.kind !== SyntaxKind.Constructor && declaration.kind !== SyntaxKind.ConstructSignature)) {
|
|
|
|
|
// When resolved signature is a call signature (and not a construct signature) the result type is any
|
|
|
|
|
if (program.getCompilerOptions().noImplicitAny) {
|
|
|
|
|
error(node, Diagnostics.new_expression_whose_target_lacks_a_construct_signature_implicitly_has_an_any_type);
|
|
|
|
|
}
|
|
|
|
|
return anyType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return getReturnTypeOfSignature(signature);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkTypeAssertion(node: TypeAssertion): Type {
|
|
|
|
|
var exprType = checkExpression(node.operand);
|
|
|
|
|
var targetType = getTypeFromTypeNode(node.type);
|
|
|
|
|
if (targetType === unknownType) return unknownType;
|
|
|
|
|
var exprType = checkExpression(node.operand, targetType);
|
|
|
|
|
var widenedType = getWidenedType(exprType);
|
|
|
|
|
if (!(isTypeAssignableTo(exprType, targetType) || isTypeAssignableTo(targetType, widenedType))) {
|
|
|
|
|
checkTypeAssignableTo(targetType, widenedType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other_Colon, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
|
|
|
|
|
}
|
|
|
|
|
return targetType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getContextualSignature(contextualType: Type) {
|
|
|
|
|
if (contextualType) {
|
|
|
|
|
var signatures = getSignaturesOfType(contextualType, SignatureKind.Call);
|
|
|
|
|
if (signatures.length === 1) {
|
|
|
|
|
var signature = signatures[0];
|
|
|
|
|
if (!signature.typeParameters) {
|
|
|
|
|
return signature;
|
|
|
|
|
}
|
|
|
|
|
if (targetType !== unknownType) {
|
|
|
|
|
var widenedType = getWidenedType(exprType);
|
|
|
|
|
if (!(isTypeAssignableTo(exprType, targetType) || isTypeAssignableTo(targetType, widenedType))) {
|
|
|
|
|
checkTypeAssignableTo(targetType, widenedType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other_Colon, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return targetType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getTypeAtPosition(signature: Signature, pos: number): Type {
|
|
|
|
|
@ -4012,9 +4135,9 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getReturnTypeFromBody(func: FunctionDeclaration, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
function getReturnTypeFromBody(func: FunctionDeclaration, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
if (func.body.kind !== SyntaxKind.FunctionBlock) {
|
|
|
|
|
var unwidenedType = checkAndMarkExpression(func.body, contextualType, contextualMapper);
|
|
|
|
|
var unwidenedType = checkAndMarkExpression(func.body, contextualMapper);
|
|
|
|
|
var widenedType = getWidenedType(unwidenedType);
|
|
|
|
|
|
|
|
|
|
if (program.getCompilerOptions().noImplicitAny && widenedType !== unwidenedType && getInnermostTypeOfNestedArrayTypes(widenedType) === anyType) {
|
|
|
|
|
@ -4025,7 +4148,7 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Aggregate the types of expressions within all the return statements.
|
|
|
|
|
var types = checkAndAggregateReturnExpressionTypes(<Block>func.body, contextualType, contextualMapper);
|
|
|
|
|
var types = checkAndAggregateReturnExpressionTypes(<Block>func.body, contextualMapper);
|
|
|
|
|
|
|
|
|
|
// Try to return the best common type if we have any return expressions.
|
|
|
|
|
if (types.length > 0) {
|
|
|
|
|
@ -4088,13 +4211,13 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Returns a set of types relating to every return expression relating to a function block.
|
|
|
|
|
function checkAndAggregateReturnExpressionTypes(body: Block, contextualType?: Type, contextualMapper?: TypeMapper): Type[] {
|
|
|
|
|
function checkAndAggregateReturnExpressionTypes(body: Block, contextualMapper?: TypeMapper): Type[] {
|
|
|
|
|
var aggregatedTypes: Type[] = [];
|
|
|
|
|
|
|
|
|
|
forEachReturnStatement(body, returnStatement => {
|
|
|
|
|
var expr = returnStatement.expression;
|
|
|
|
|
if (expr) {
|
|
|
|
|
var type = checkAndMarkExpression(expr, contextualType, contextualMapper);
|
|
|
|
|
var type = checkAndMarkExpression(expr, contextualMapper);
|
|
|
|
|
if (!contains(aggregatedTypes, type)) {
|
|
|
|
|
aggregatedTypes.push(type);
|
|
|
|
|
}
|
|
|
|
|
@ -4147,42 +4270,48 @@ module ts {
|
|
|
|
|
error(func.type, Diagnostics.A_function_whose_declared_type_is_neither_void_nor_any_must_return_a_value_or_consist_of_a_single_throw_statement);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkFunctionExpression(node: FunctionExpression, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
function checkFunctionExpression(node: FunctionExpression, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
// The identityMapper object is used to indicate that function expressions are wildcards
|
|
|
|
|
if (contextualMapper === identityMapper) {
|
|
|
|
|
return anyFunctionType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var type = getTypeOfSymbol(node.symbol);
|
|
|
|
|
var links = getNodeLinks(node);
|
|
|
|
|
|
|
|
|
|
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
|
|
|
|
|
var signature = getSignaturesOfType(type, SignatureKind.Call)[0];
|
|
|
|
|
var contextualSignature = getContextualSignature(contextualType);
|
|
|
|
|
if (contextualSignature) {
|
|
|
|
|
if (!node.typeParameters && !forEach(node.parameters, p => p.type)) {
|
|
|
|
|
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
|
|
|
|
|
}
|
|
|
|
|
if (!node.type) {
|
|
|
|
|
signature.resolvedReturnType = resolvingType;
|
|
|
|
|
var returnType = getReturnTypeFromBody(node, getReturnTypeOfSignature(contextualSignature), contextualMapper);
|
|
|
|
|
if (signature.resolvedReturnType === resolvingType) {
|
|
|
|
|
signature.resolvedReturnType = returnType;
|
|
|
|
|
var type = getTypeOfSymbol(node.symbol);
|
|
|
|
|
// Check if function expression is contextually typed and assign parameter types if so
|
|
|
|
|
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
|
|
|
|
|
var contextualSignature = getContextualSignature(node);
|
|
|
|
|
// If a type check is started at a function expression that is an argument of a function call, obtaining the
|
|
|
|
|
// contextual type may recursively get back to here during overload resolution of the call. If so, we will have
|
|
|
|
|
// already assigned contextual types.
|
|
|
|
|
if (!(links.flags & NodeCheckFlags.ContextChecked)) {
|
|
|
|
|
links.flags |= NodeCheckFlags.ContextChecked;
|
|
|
|
|
if (contextualSignature) {
|
|
|
|
|
var signature = getSignaturesOfType(type, SignatureKind.Call)[0];
|
|
|
|
|
if (isContextSensitiveExpression(node)) {
|
|
|
|
|
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
|
|
|
|
|
}
|
|
|
|
|
if (!node.type) {
|
|
|
|
|
signature.resolvedReturnType = resolvingType;
|
|
|
|
|
var returnType = getReturnTypeFromBody(node, contextualMapper);
|
|
|
|
|
if (signature.resolvedReturnType === resolvingType) {
|
|
|
|
|
signature.resolvedReturnType = returnType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (fullTypeCheck && !(links.flags & NodeCheckFlags.TypeChecked)) {
|
|
|
|
|
checkSignatureDeclaration(node);
|
|
|
|
|
if (node.type) {
|
|
|
|
|
checkIfNonVoidFunctionHasReturnExpressionsOrSingleThrowStatment(node, getTypeFromTypeNode(node.type));
|
|
|
|
|
}
|
|
|
|
|
if (node.body.kind === SyntaxKind.FunctionBlock) {
|
|
|
|
|
checkSourceElement(node.body);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
var returnType = getReturnTypeOfSignature(signature);
|
|
|
|
|
var exprType = checkExpression(node.body);
|
|
|
|
|
if (node.type) {
|
|
|
|
|
// Use default error messages for this check
|
|
|
|
|
checkTypeAssignableTo(checkExpression(node.body, returnType), returnType, node.body, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
|
|
|
|
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, undefined, undefined);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
links.flags |= NodeCheckFlags.TypeChecked;
|
|
|
|
|
@ -4312,13 +4441,10 @@ module ts {
|
|
|
|
|
return booleanType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkBinaryExpression(node: BinaryExpression, contextualType?: Type, contextualMapper?: TypeMapper) {
|
|
|
|
|
function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) {
|
|
|
|
|
var operator = node.operator;
|
|
|
|
|
var leftContextualType = operator === SyntaxKind.BarBarToken ? contextualType : undefined
|
|
|
|
|
var leftType = checkExpression(node.left, leftContextualType, contextualMapper);
|
|
|
|
|
var rightContextualType = operator >= SyntaxKind.FirstAssignment && operator <= SyntaxKind.LastAssignment ? leftType :
|
|
|
|
|
operator === SyntaxKind.BarBarToken ? contextualType || leftType : undefined;
|
|
|
|
|
var rightType = checkExpression(node.right, rightContextualType, contextualMapper);
|
|
|
|
|
var leftType = checkExpression(node.left, contextualMapper);
|
|
|
|
|
var rightType = checkExpression(node.right, contextualMapper);
|
|
|
|
|
switch (operator) {
|
|
|
|
|
case SyntaxKind.AsteriskToken:
|
|
|
|
|
case SyntaxKind.AsteriskEqualsToken:
|
|
|
|
|
@ -4410,7 +4536,7 @@ module ts {
|
|
|
|
|
case SyntaxKind.AmpersandAmpersandToken:
|
|
|
|
|
return rightType;
|
|
|
|
|
case SyntaxKind.BarBarToken:
|
|
|
|
|
return getBestCommonType([leftType, rightType], isInferentialContext(contextualMapper) ? undefined : contextualType);
|
|
|
|
|
return getBestCommonType([leftType, rightType], isInferentialContext(contextualMapper) ? undefined : getContextualType(node));
|
|
|
|
|
case SyntaxKind.EqualsToken:
|
|
|
|
|
checkAssignmentOperator(rightType);
|
|
|
|
|
return rightType;
|
|
|
|
|
@ -4440,40 +4566,46 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkConditionalExpression(node: ConditionalExpression, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
function checkConditionalExpression(node: ConditionalExpression, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
checkExpression(node.condition);
|
|
|
|
|
var type1 = checkExpression(node.whenTrue, contextualType, contextualMapper);
|
|
|
|
|
var type2 = checkExpression(node.whenFalse, contextualType, contextualMapper);
|
|
|
|
|
var resultType = getBestCommonType([type1, type2], isInferentialContext(contextualMapper) ? undefined : contextualType, true);
|
|
|
|
|
var type1 = checkExpression(node.whenTrue, contextualMapper);
|
|
|
|
|
var type2 = checkExpression(node.whenFalse, contextualMapper);
|
|
|
|
|
var contextualType = isInferentialContext(contextualMapper) ? undefined : getContextualType(node);
|
|
|
|
|
var resultType = getBestCommonType([type1, type2], contextualType, true);
|
|
|
|
|
if (!resultType) {
|
|
|
|
|
|
|
|
|
|
if (contextualType && !isInferentialContext(contextualMapper)) {
|
|
|
|
|
if (contextualType) {
|
|
|
|
|
error(node, Diagnostics.No_best_common_type_exists_between_0_1_and_2, typeToString(contextualType), typeToString(type1), typeToString(type2));
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
error(node, Diagnostics.No_best_common_type_exists_between_0_and_1, typeToString(type1), typeToString(type2));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resultType = emptyObjectType;
|
|
|
|
|
}
|
|
|
|
|
return resultType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkAndMarkExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
var result = checkExpression(node, contextualType, contextualMapper);
|
|
|
|
|
function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
var saveContextualType = node.contextualType;
|
|
|
|
|
node.contextualType = contextualType;
|
|
|
|
|
var result = checkExpression(node, contextualMapper);
|
|
|
|
|
node.contextualType = saveContextualType;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkAndMarkExpression(node: Expression, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
var result = checkExpression(node, contextualMapper);
|
|
|
|
|
getNodeLinks(node).flags |= NodeCheckFlags.TypeChecked;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Checks an expression and returns its type. The contextualType parameter provides a contextual type for
|
|
|
|
|
// the check or is undefined if there is no contextual type. The contextualMapper parameter serves two
|
|
|
|
|
// purposes: When contextualMapper is not undefined and not equal to the identityMapper function object
|
|
|
|
|
// it provides a type mapper to use during inferential typing (the contextual type is then a generic type).
|
|
|
|
|
// When contextualMapper is equal to the identityMapper function object, it serves as an indicator that all
|
|
|
|
|
// contained function and arrow expressions should be considered to have the wildcard function type; this
|
|
|
|
|
// form of type check is used during overload resolution to exclude contextually typed function and arrow
|
|
|
|
|
// expressions in the initial phase.
|
|
|
|
|
function checkExpression(node: Expression, contextualType?: Type, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
// Checks an expression and returns its type. The contextualMapper parameter serves two purposes: When
|
|
|
|
|
// contextualMapper is not undefined and not equal to the identityMapper function object it indicates that the
|
|
|
|
|
// expression is being inferentially typed (section 4.12.2 in spec) and provides the type mapper to use in
|
|
|
|
|
// conjuction with the generic contextual type. When contextualMapper is equal to the identityMapper function
|
|
|
|
|
// object, it serves as an indicator that all contained function and arrow expressions should be considered to
|
|
|
|
|
// have the wildcard function type; this form of type check is used during overload resolution to exclude
|
|
|
|
|
// contextually typed function and arrow expressions in the initial phase.
|
|
|
|
|
function checkExpression(node: Expression, contextualMapper?: TypeMapper): Type {
|
|
|
|
|
switch (node.kind) {
|
|
|
|
|
case SyntaxKind.Identifier:
|
|
|
|
|
return checkIdentifier(<Identifier>node);
|
|
|
|
|
@ -4495,32 +4627,31 @@ module ts {
|
|
|
|
|
case SyntaxKind.QualifiedName:
|
|
|
|
|
return checkPropertyAccess(<QualifiedName>node);
|
|
|
|
|
case SyntaxKind.ArrayLiteral:
|
|
|
|
|
return checkArrayLiteral(<ArrayLiteral>node, contextualType, contextualMapper);
|
|
|
|
|
return checkArrayLiteral(<ArrayLiteral>node, contextualMapper);
|
|
|
|
|
case SyntaxKind.ObjectLiteral:
|
|
|
|
|
return checkObjectLiteral(<ObjectLiteral>node, contextualType, contextualMapper);
|
|
|
|
|
return checkObjectLiteral(<ObjectLiteral>node, contextualMapper);
|
|
|
|
|
case SyntaxKind.PropertyAccess:
|
|
|
|
|
return checkPropertyAccess(<PropertyAccess>node);
|
|
|
|
|
case SyntaxKind.IndexedAccess:
|
|
|
|
|
return checkIndexedAccess(<IndexedAccess>node);
|
|
|
|
|
case SyntaxKind.CallExpression:
|
|
|
|
|
return checkCallExpression(<CallExpression>node);
|
|
|
|
|
case SyntaxKind.NewExpression:
|
|
|
|
|
return checkNewExpression(<NewExpression>node);
|
|
|
|
|
return checkCallExpression(<CallExpression>node);
|
|
|
|
|
case SyntaxKind.TypeAssertion:
|
|
|
|
|
return checkTypeAssertion(<TypeAssertion>node);
|
|
|
|
|
case SyntaxKind.ParenExpression:
|
|
|
|
|
return checkExpression((<ParenExpression>node).expression);
|
|
|
|
|
case SyntaxKind.FunctionExpression:
|
|
|
|
|
case SyntaxKind.ArrowFunction:
|
|
|
|
|
return checkFunctionExpression(<FunctionExpression>node, contextualType, contextualMapper);
|
|
|
|
|
return checkFunctionExpression(<FunctionExpression>node, contextualMapper);
|
|
|
|
|
case SyntaxKind.PrefixOperator:
|
|
|
|
|
return checkPrefixExpression(<UnaryExpression>node);
|
|
|
|
|
case SyntaxKind.PostfixOperator:
|
|
|
|
|
return checkPostfixExpression(<UnaryExpression>node);
|
|
|
|
|
case SyntaxKind.BinaryExpression:
|
|
|
|
|
return checkBinaryExpression(<BinaryExpression>node, contextualType, contextualMapper);
|
|
|
|
|
return checkBinaryExpression(<BinaryExpression>node, contextualMapper);
|
|
|
|
|
case SyntaxKind.ConditionalExpression:
|
|
|
|
|
return checkConditionalExpression(<ConditionalExpression>node, contextualType, contextualMapper);
|
|
|
|
|
return checkConditionalExpression(<ConditionalExpression>node, contextualMapper);
|
|
|
|
|
}
|
|
|
|
|
return unknownType;
|
|
|
|
|
}
|
|
|
|
|
@ -5325,7 +5456,7 @@ module ts {
|
|
|
|
|
if (node.initializer) {
|
|
|
|
|
if (!(getNodeLinks(node.initializer).flags & NodeCheckFlags.TypeChecked)) {
|
|
|
|
|
// Use default messages
|
|
|
|
|
checkTypeAssignableTo(checkAndMarkExpression(node.initializer, type), type, node, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
|
|
|
|
checkTypeAssignableTo(checkAndMarkExpression(node.initializer), type, node, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -5446,12 +5577,12 @@ module ts {
|
|
|
|
|
func.type ||
|
|
|
|
|
(func.kind === SyntaxKind.GetAccessor && getSetAccessorTypeAnnotationNode(<AccessorDeclaration>getDeclarationOfKind(func.symbol, SyntaxKind.SetAccessor)));
|
|
|
|
|
if (checkAssignability) {
|
|
|
|
|
checkTypeAssignableTo(checkExpression(node.expression, returnType), returnType, node.expression, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
|
|
|
|
checkTypeAssignableTo(checkExpression(node.expression), returnType, node.expression, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
|
|
|
|
|
}
|
|
|
|
|
else if (func.kind == SyntaxKind.Constructor) {
|
|
|
|
|
// constructor doesn't have explicit return type annontation and yet its return type is known - declaring type
|
|
|
|
|
// handle constructors and issue specialized error message for them.
|
|
|
|
|
if (!isTypeAssignableTo(checkExpression(node.expression, returnType), returnType)) {
|
|
|
|
|
if (!isTypeAssignableTo(checkExpression(node.expression), returnType)) {
|
|
|
|
|
error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -6048,9 +6179,12 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Fully type check a source file and collect the relevant diagnostics. The fullTypeCheck flag is true during this
|
|
|
|
|
// operation, but otherwise is false when the compiler is used by the language service.
|
|
|
|
|
function checkSourceFile(node: SourceFile) {
|
|
|
|
|
var links = getNodeLinks(node);
|
|
|
|
|
if (!(links.flags & NodeCheckFlags.TypeChecked)) {
|
|
|
|
|
fullTypeCheck = true;
|
|
|
|
|
emitExtends = false;
|
|
|
|
|
potentialThisCollisions.length = 0;
|
|
|
|
|
forEach(node.statements, checkSourceElement);
|
|
|
|
|
@ -6067,6 +6201,7 @@ module ts {
|
|
|
|
|
}
|
|
|
|
|
if (emitExtends) links.flags |= NodeCheckFlags.EmitExtends;
|
|
|
|
|
links.flags |= NodeCheckFlags.TypeChecked;
|
|
|
|
|
fullTypeCheck = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|