Merge branch 'master' into completionFixes

This commit is contained in:
Mohamed Hegazy
2014-10-28 09:10:03 -07:00
49 changed files with 636 additions and 332 deletions

View File

@@ -130,6 +130,7 @@ module ts {
var emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
var anyFunctionType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
var noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
var inferenceFailureType = 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);
@@ -3169,33 +3170,40 @@ module ts {
var identityRelation: Map<boolean> = {};
function isTypeIdenticalTo(source: Type, target: Type): boolean {
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
}
function isTypeSubtypeOf(source: Type, target: Type): boolean {
return checkTypeSubtypeOf(source, target, /*errorNode*/ undefined, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
return checkTypeSubtypeOf(source, target, /*errorNode*/ undefined);
}
function checkTypeSubtypeOf(source: Type, target: Type, errorNode: Node, chainedMessage: DiagnosticMessage, terminalMessage: DiagnosticMessage): boolean {
return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, chainedMessage, terminalMessage);
function checkTypeSubtypeOf(
source: Type,
target: Type,
errorNode: Node,
chainedMessage?: DiagnosticMessage,
terminalMessage?: DiagnosticMessage,
containingMessageChain?: DiagnosticMessageChain): boolean {
return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, chainedMessage, terminalMessage, containingMessageChain);
}
function isTypeAssignableTo(source: Type, target: Type): boolean {
return checkTypeAssignableTo(source, target, /*errorNode*/ undefined, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
return checkTypeAssignableTo(source, target, /*errorNode*/ undefined);
}
function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, chainedMessage: DiagnosticMessage, terminalMessage: DiagnosticMessage): boolean {
function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, chainedMessage?: DiagnosticMessage, terminalMessage?: DiagnosticMessage): boolean {
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, chainedMessage, terminalMessage);
}
function isTypeRelatedTo(source: Type, target: Type, relation: Map<boolean>): boolean {
return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
return checkTypeRelatedTo(source, target, relation, /*errorNode*/ undefined);
}
function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
var sourceType = getOrCreateTypeFromSignature(source);
var targetType = getOrCreateTypeFromSignature(target);
return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined, /*chainedMessage*/ undefined, /*terminalMessage*/ undefined);
return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
}
function isPropertyIdenticalTo(sourceProp: Symbol, targetProp: Symbol): boolean {
@@ -3259,7 +3267,15 @@ module ts {
}
}
function checkTypeRelatedTo(source: Type, target: Type, relation: Map<boolean>, errorNode: Node, chainedMessage: DiagnosticMessage, terminalMessage: DiagnosticMessage): boolean {
function checkTypeRelatedTo(
source: Type,
target: Type,
relation: Map<boolean>,
errorNode: Node,
chainedMessage?: DiagnosticMessage,
terminalMessage?: DiagnosticMessage,
containingMessageChain?: DiagnosticMessageChain): boolean {
var errorInfo: DiagnosticMessageChain;
var sourceStack: ObjectType[];
var targetStack: ObjectType[];
@@ -3274,6 +3290,9 @@ module ts {
error(errorNode, Diagnostics.Excessive_stack_depth_comparing_types_0_and_1, typeToString(source), typeToString(target));
}
else if (errorInfo) {
if (containingMessageChain) {
errorInfo = concatenateDiagnosticMessageChains(containingMessageChain, errorInfo);
}
addDiagnostic(createDiagnosticForNodeFromMessageChain(errorNode, errorInfo, program.getCompilerHost().getNewLine()));
}
return result;
@@ -3769,6 +3788,43 @@ module ts {
return forEach(types, t => isSupertypeOfEach(t, types) ? t : undefined);
}
function reportNoCommonSupertypeError(types: Type[], errorLocation: Node, errorMessageChainHead: DiagnosticMessageChain): void {
var bestSupertype: Type;
var bestSupertypeDownfallType: Type; // The type that caused bestSupertype not to be the common supertype
var bestSupertypeScore = 0;
for (var i = 0; i < types.length; i++) {
var score = 0;
var downfallType: Type = undefined;
for (var j = 0; j < types.length; j++) {
if (isTypeSubtypeOf(types[j], types[i])) {
score++;
}
else if (!downfallType) {
downfallType = types[j];
}
}
if (score > bestSupertypeScore) {
bestSupertype = types[i];
bestSupertypeDownfallType = downfallType;
bestSupertypeScore = score;
}
// types.length - 1 is the maximum score, given that getCommonSupertype returned false
if (bestSupertypeScore === types.length - 1) {
break;
}
}
// In the following errors, the {1} slot is before the {0} slot because checkTypeSubtypeOf supplies the
// subtype as the first argument to the error
checkTypeSubtypeOf(bestSupertypeDownfallType, bestSupertype, errorLocation,
Diagnostics.Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0_Colon,
Diagnostics.Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0,
errorMessageChainHead);
}
function isTypeOfObjectLiteral(type: Type): boolean {
return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
}
@@ -3876,8 +3932,8 @@ module ts {
callback(s, t);
}
}
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
function createInferenceContext(typeParameters: TypeParameter[], inferUnionTypes: boolean): InferenceContext {
var inferences: Type[][] = [];
for (var i = 0; i < typeParameters.length; i++) inferences.push([]);
return {
@@ -4025,30 +4081,33 @@ module ts {
}
function getInferredType(context: InferenceContext, index: number): Type {
var result = context.inferredTypes[index];
if (!result) {
var inferredType = context.inferredTypes[index];
if (!inferredType) {
var inferences = context.inferences[index];
if (inferences.length) {
// Infer widened union or supertype, or the undefined type for no common supertype
var unionOrSuperType = context.inferUnionTypes ? getUnionType(inferences) : getCommonSupertype(inferences);
var inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : undefinedType;
inferredType = unionOrSuperType ? getWidenedType(unionOrSuperType) : inferenceFailureType;
}
else {
// Infer the empty object type when no inferences were made
inferredType = emptyObjectType;
}
var constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
var result = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
context.inferredTypes[index] = result;
if (inferredType !== inferenceFailureType) {
var constraint = getConstraintOfTypeParameter(context.typeParameters[index]);
inferredType = constraint && !isTypeAssignableTo(inferredType, constraint) ? constraint : inferredType;
}
context.inferredTypes[index] = inferredType;
}
return result;
return inferredType;
}
function getInferredTypes(context: InferenceContext): Type[] {
for (var i = 0; i < context.inferredTypes.length; i++) {
getInferredType(context, i);
}
context.inferences = undefined;
return context.inferredTypes;
}
@@ -5098,9 +5157,9 @@ module ts {
return getSignatureInstantiation(signature, getInferredTypes(context));
}
function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument?: boolean[]): Type[] {
var typeParameters = signature.typeParameters;
var context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
function inferTypeArguments(signature: Signature, args: Expression[], excludeArgument?: boolean[]): InferenceContext {
var typeParameters = signature.typeParameters;
var context = createInferenceContext(typeParameters, /*inferUnionTypes*/ false);
var mapper = createInferenceMapper(context);
// First infer from arguments that are not context sensitive
for (var i = 0; i < args.length; i++) {
@@ -5125,23 +5184,36 @@ module ts {
}
}
var inferredTypes = getInferredTypes(context);
// Inference has failed if the undefined type is in list of inferences
return contains(inferredTypes, undefinedType) ? undefined : inferredTypes;
// Inference has failed if the inferenceFailureType type is in list of inferences
context.failedTypeParameterIndex = indexOf(inferredTypes, inferenceFailureType);
// Wipe out the inferenceFailureType from the array so that error recovery can work properly
for (var i = 0; i < inferredTypes.length; i++) {
if (inferredTypes[i] === inferenceFailureType) {
inferredTypes[i] = unknownType;
}
}
return context;
}
function checkTypeArguments(signature: Signature, typeArguments: TypeNode[]): Type[] {
function checkTypeArguments(signature: Signature, typeArguments: TypeNode[], typeArgumentResultTypes: Type[], reportErrors: boolean): boolean {
var typeParameters = signature.typeParameters;
var result: Type[] = [];
var typeArgumentsAreAssignable = true;
for (var i = 0; i < typeParameters.length; i++) {
var typeArgNode = typeArguments[i];
var typeArgument = getTypeFromTypeNode(typeArgNode);
var constraint = getConstraintOfTypeParameter(typeParameters[i]);
if (constraint && fullTypeCheck) {
checkTypeAssignableTo(typeArgument, constraint, typeArgNode, Diagnostics.Type_0_does_not_satisfy_the_constraint_1_Colon, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
// Do not push on this array! It has a preallocated length
typeArgumentResultTypes[i] = typeArgument;
if (typeArgumentsAreAssignable /* so far */) {
var constraint = getConstraintOfTypeParameter(typeParameters[i]);
if (constraint) {
typeArgumentsAreAssignable = checkTypeAssignableTo(typeArgument, constraint, reportErrors ? typeArgNode : undefined,
Diagnostics.Type_0_does_not_satisfy_the_constraint_1_Colon, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
}
}
result.push(typeArgument);
}
return result;
return typeArgumentsAreAssignable;
}
function checkApplicableSignature(node: CallExpression, signature: Signature, relation: Map<boolean>, excludeArgument: boolean[], reportErrors: boolean) {
@@ -5185,47 +5257,84 @@ module ts {
excludeArgument[i] = true;
}
}
var relation = candidates.length === 1 ? assignableRelation : subtypeRelation;
var lastCandidate: Signature;
while (true) {
for (var i = 0; i < candidates.length; i++) {
if (!signatureHasCorrectArity(node, candidates[i])) {
continue;
}
while (true) {
var candidate = candidates[i];
if (candidate.typeParameters) {
var typeArguments = node.typeArguments ?
checkTypeArguments(candidate, node.typeArguments) :
inferTypeArguments(candidate, args, excludeArgument);
if (!typeArguments) {
break;
}
candidate = getSignatureInstantiation(candidate, typeArguments);
}
lastCandidate = candidate;
if (!checkApplicableSignature(node, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
break;
}
var index = excludeArgument ? indexOf(excludeArgument, true) : -1;
if (index < 0) {
return candidate;
}
excludeArgument[index] = false;
}
}
if (relation === assignableRelation) {
break;
}
relation = assignableRelation;
// The following variables are captured and modified by calls to chooseOverload.
// If overload resolution or type argument inference fails, we want to report the
// best error possible. The best error is one which says that an argument was not
// assignable to a parameter. This implies that everything else about the overload
// was fine. So if there is any overload that is only incorrect because of an
// argument, we will report an error on that one.
//
// function foo(s: string) {}
// function foo(n: number) {} // Report argument error on this overload
// function foo() {}
// foo(true);
//
// If none of the overloads even made it that far, there are two possibilities.
// There was a problem with type arguments for some overload, in which case
// report an error on that. Or none of the overloads even had correct arity,
// in which case give an arity error.
//
// function foo<T>(x: T, y: T) {} // Report type argument inference error
// function foo() {}
// foo(0, true);
//
var candidateForArgumentError: Signature;
var candidateForTypeArgumentError: Signature;
var resultOfFailedInference: InferenceContext;
var result: Signature;
// Section 4.12.1:
// if the candidate list contains one or more signatures for which the type of each argument
// expression is a subtype of each corresponding parameter type, the return type of the first
// of those signatures becomes the return type of the function call.
// Otherwise, the return type of the first signature in the candidate list becomes the return
// type of the function call.
//
// Whether the call is an error is determined by assignability of the arguments. The subtype pass
// is just important for choosing the best signature. So in the case where there is only one
// signature, the subtype pass is useless. So skipping it is an optimization.
if (candidates.length > 1) {
result = chooseOverload(candidates, subtypeRelation, excludeArgument);
}
if (!result) {
// Reinitialize these pointers for round two
candidateForArgumentError = undefined;
candidateForTypeArgumentError = undefined;
resultOfFailedInference = undefined;
result = chooseOverload(candidates, assignableRelation, excludeArgument);
}
if (result) {
return result;
}
// No signatures were applicable. Now report errors based on the last applicable signature with
// no arguments excluded from assignability checks.
// If candidate is undefined, it means that no candidates had a suitable arity. In that case,
// skip the checkApplicableSignature check.
if (lastCandidate) {
checkApplicableSignature(node, lastCandidate, relation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
if (candidateForArgumentError) {
// excludeArgument is undefined, in this case also equivalent to [undefined, undefined, ...]
// The importance of excludeArgument is to prevent us from typing function expression parameters
// in arguments too early. If possible, we'd like to only type them once we know the correct
// overload. However, this matters for the case where the call is correct. When the call is
// an error, we don't need to exclude any arguments, although it would cause no harm to do so.
checkApplicableSignature(node, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
}
else if (candidateForTypeArgumentError) {
if (node.typeArguments) {
checkTypeArguments(candidateForTypeArgumentError, node.typeArguments, [], /*reportErrors*/ true)
}
else {
Debug.assert(resultOfFailedInference.failedTypeParameterIndex >= 0);
var failedTypeParameter = candidateForTypeArgumentError.typeParameters[resultOfFailedInference.failedTypeParameterIndex];
var inferenceCandidates = resultOfFailedInference.inferences[resultOfFailedInference.failedTypeParameterIndex];
var diagnosticChainHead = chainDiagnosticMessages(/*details*/ undefined, // details will be provided by call to reportNoCommonSupertypeError
Diagnostics.The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly_Colon,
typeToString(failedTypeParameter));
reportNoCommonSupertypeError(inferenceCandidates, node.func, diagnosticChainHead);
}
}
else {
error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target);
@@ -5246,6 +5355,70 @@ module ts {
return resolveErrorCall(node);
function chooseOverload(candidates: Signature[], relation: Map<boolean>, excludeArgument: boolean[]) {
for (var i = 0; i < candidates.length; i++) {
if (!signatureHasCorrectArity(node, candidates[i])) {
continue;
}
var originalCandidate = candidates[i];
var inferenceResult: InferenceContext;
while (true) {
var candidate = originalCandidate;
if (candidate.typeParameters) {
var typeArgumentTypes: Type[];
var typeArgumentsAreValid: boolean;
if (node.typeArguments) {
typeArgumentTypes = new Array<Type>(candidate.typeParameters.length);
typeArgumentsAreValid = checkTypeArguments(candidate, node.typeArguments, typeArgumentTypes, /*reportErrors*/ false)
}
else {
inferenceResult = inferTypeArguments(candidate, args, excludeArgument);
typeArgumentsAreValid = inferenceResult.failedTypeParameterIndex < 0;
typeArgumentTypes = inferenceResult.inferredTypes;
}
if (!typeArgumentsAreValid) {
break;
}
candidate = getSignatureInstantiation(candidate, typeArgumentTypes);
}
if (!checkApplicableSignature(node, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
break;
}
var index = excludeArgument ? indexOf(excludeArgument, true) : -1;
if (index < 0) {
return candidate;
}
excludeArgument[index] = false;
}
// A post-mortem of this iteration of the loop. The signature was not applicable,
// so we want to track it as a candidate for reporting an error. If the candidate
// had no type parameters, or had no issues related to type arguments, we can
// report an error based on the arguments. If there was an issue with type
// arguments, then we can only report an error based on the type arguments.
if (originalCandidate.typeParameters) {
var instantiatedCandidate = candidate;
if (typeArgumentsAreValid) {
candidateForArgumentError = instantiatedCandidate;
}
else {
candidateForTypeArgumentError = originalCandidate;
if (!node.typeArguments) {
resultOfFailedInference = inferenceResult;
}
}
}
else {
Debug.assert(originalCandidate === candidate);
candidateForArgumentError = originalCandidate;
}
}
return undefined;
}
// The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
// A nit here is that we reorder only signatures that belong to the same symbol,
// so order how inherited signatures are processed is still preserved.

View File

@@ -274,6 +274,12 @@ module ts {
};
}
export function concatenateDiagnosticMessageChains(headChain: DiagnosticMessageChain, tailChain: DiagnosticMessageChain): DiagnosticMessageChain {
Debug.assert(!headChain.next);
headChain.next = tailChain;
return headChain;
}
export function flattenDiagnosticChain(file: SourceFile, start: number, length: number, diagnosticChain: DiagnosticMessageChain, newLine: string): Diagnostic {
Debug.assert(start >= 0, "start must be non-negative, is " + start);
Debug.assert(length >= 0, "length must be non-negative, is " + length);

View File

@@ -271,6 +271,9 @@ module ts {
Left_hand_side_of_assignment_expression_cannot_be_a_constant: { code: 2450, category: DiagnosticCategory.Error, key: "Left-hand side of assignment expression cannot be a constant.", isEarly: true },
Cannot_redeclare_block_scoped_variable_0: { code: 2451, category: DiagnosticCategory.Error, key: "Cannot redeclare block-scoped variable '{0}'.", isEarly: true },
An_enum_member_cannot_have_a_numeric_name: { code: 2452, category: DiagnosticCategory.Error, key: "An enum member cannot have a numeric name." },
The_type_argument_for_type_parameter_0_cannot_be_inferred_from_the_usage_Consider_specifying_the_type_arguments_explicitly_Colon: { code: 2453, category: DiagnosticCategory.Error, key: "The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly:" },
Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0_Colon: { code: 2454, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}':" },
Type_argument_candidate_1_is_not_a_valid_type_argument_because_it_is_not_a_supertype_of_candidate_0: { code: 2455, category: DiagnosticCategory.Error, key: "Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'." },
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },

View File

@@ -1080,6 +1080,18 @@
"category": "Error",
"code": 2452
},
"The type argument for type parameter '{0}' cannot be inferred from the usage. Consider specifying the type arguments explicitly:": {
"category": "Error",
"code": 2453
},
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}':": {
"category": "Error",
"code": 2454
},
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": {
"category": "Error",
"code": 2455
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",

View File

@@ -766,7 +766,7 @@ module ts {
}
export enum SymbolFlags {
FunctionScopedVariable = 0x00000001, // Variable (var) or parameter
FunctionScopedVariable = 0x00000001, // Variable (var) or parameter
Property = 0x00000002, // Property or enum member
EnumMember = 0x00000004, // Enum member
Function = 0x00000008, // Function
@@ -1034,6 +1034,8 @@ module ts {
inferenceCount: number; // Incremented for every inference made (whether new or not)
inferences: Type[][]; // Inferences made for each type parameter
inferredTypes: Type[]; // Inferred type for each type parameter
failedTypeParameterIndex?: number; // Index of type parameter for which inference failed
// It is optional because in contextual signature instantiation, nothing fails
}
export interface DiagnosticMessage {

View File

@@ -3859,7 +3859,7 @@ module ts {
if (symbol.getFlags() && (SymbolFlags.Property | SymbolFlags.Method)) {
var privateDeclaration = forEach(symbol.getDeclarations(), d => (d.flags & NodeFlags.Private) ? d : undefined);
if (privateDeclaration) {
return privateDeclaration.parent;
return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration);
}
}