@@ -5818,10 +5818,74 @@ module ts {
5818
5818
return unknownSignature;
5819
5819
}
5820
5820
5821
+ // Re-order candidate signatures into the result array. Assumes the result array to be empty.
5822
+ // The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
5823
+ // A nit here is that we reorder only signatures that belong to the same symbol,
5824
+ // so order how inherited signatures are processed is still preserved.
5825
+ // interface A { (x: string): void }
5826
+ // interface B extends A { (x: 'foo'): string }
5827
+ // var b: B;
5828
+ // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
5829
+ function reorderCandidates(signatures: Signature[], result: Signature[]): void {
5830
+ var lastParent: Node;
5831
+ var lastSymbol: Symbol;
5832
+ var cutoffIndex: number = 0;
5833
+ var index: number;
5834
+ var specializedIndex: number = -1;
5835
+ var spliceIndex: number;
5836
+ Debug.assert(!result.length);
5837
+ for (var i = 0; i < signatures.length; i++) {
5838
+ var signature = signatures[i];
5839
+ var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
5840
+ var parent = signature.declaration && signature.declaration.parent;
5841
+ if (!lastSymbol || symbol === lastSymbol) {
5842
+ if (lastParent && parent === lastParent) {
5843
+ index++;
5844
+ }
5845
+ else {
5846
+ lastParent = parent;
5847
+ index = cutoffIndex;
5848
+ }
5849
+ }
5850
+ else {
5851
+ // current declaration belongs to a different symbol
5852
+ // set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
5853
+ index = cutoffIndex = result.length;
5854
+ lastParent = parent;
5855
+ }
5856
+ lastSymbol = symbol;
5857
+
5858
+ // specialized signatures always need to be placed before non-specialized signatures regardless
5859
+ // of the cutoff position; see GH#1133
5860
+ if (signature.hasStringLiterals) {
5861
+ specializedIndex++;
5862
+ spliceIndex = specializedIndex;
5863
+ // The cutoff index always needs to be greater than or equal to the specialized signature index
5864
+ // in order to prevent non-specialized signatures from being added before a specialized
5865
+ // signature.
5866
+ cutoffIndex++;
5867
+ }
5868
+ else {
5869
+ spliceIndex = index;
5870
+ }
5871
+
5872
+ result.splice(spliceIndex, 0, signature);
5873
+ }
5874
+ }
5875
+
5876
+ function getSpreadArgumentIndex(args: Expression[]): number {
5877
+ for (var i = 0; i < args.length; i++) {
5878
+ if (args[i].kind === SyntaxKind.SpreadElementExpression) {
5879
+ return i;
5880
+ }
5881
+ }
5882
+ return -1;
5883
+ }
5884
+
5821
5885
function hasCorrectArity(node: CallLikeExpression, args: Expression[], signature: Signature) {
5822
- var adjustedArgCount: number;
5823
- var typeArguments: NodeArray<TypeNode>;
5824
- var callIsIncomplete: boolean;
5886
+ var adjustedArgCount: number; // Apparent number of arguments we will have in this call
5887
+ var typeArguments: NodeArray<TypeNode>; // Type arguments (undefined if none)
5888
+ var callIsIncomplete: boolean; // In incomplete call we want to be lenient when we have too few arguments
5825
5889
5826
5890
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
5827
5891
var tagExpression = <TaggedTemplateExpression>node;
@@ -5866,35 +5930,29 @@ module ts {
5866
5930
typeArguments = callExpression.typeArguments;
5867
5931
}
5868
5932
5869
- Debug.assert(adjustedArgCount !== undefined, "'adjustedArgCount' undefined");
5870
- Debug.assert(callIsIncomplete !== undefined, "'callIsIncomplete' undefined");
5871
-
5872
- return checkArity(adjustedArgCount, typeArguments, callIsIncomplete, signature);
5873
-
5874
- /**
5875
- * @param adjustedArgCount The "apparent" number of arguments that we will have in this call.
5876
- * @param typeArguments Type arguments node of the call if it exists; undefined otherwise.
5877
- * @param callIsIncomplete Whether or not a call is unfinished, and we should be "lenient" when we have too few arguments.
5878
- * @param signature The signature whose arity we are comparing.
5879
- */
5880
- function checkArity(adjustedArgCount: number, typeArguments: NodeArray<TypeNode>, callIsIncomplete: boolean, signature: Signature): boolean {
5881
- // Too many arguments implies incorrect arity.
5882
- if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) {
5883
- return false;
5884
- }
5933
+ // If the user supplied type arguments, but the number of type arguments does not match
5934
+ // the declared number of type parameters, the call has an incorrect arity.
5935
+ var hasRightNumberOfTypeArgs = !typeArguments ||
5936
+ (signature.typeParameters && typeArguments.length === signature.typeParameters.length);
5937
+ if (!hasRightNumberOfTypeArgs) {
5938
+ return false;
5939
+ }
5885
5940
5886
- // If the user supplied type arguments, but the number of type arguments does not match
5887
- // the declared number of type parameters, the call has an incorrect arity.
5888
- var hasRightNumberOfTypeArgs = !typeArguments ||
5889
- (signature.typeParameters && typeArguments.length === signature.typeParameters.length);
5890
- if (!hasRightNumberOfTypeArgs) {
5891
- return false;
5892
- }
5941
+ // If spread arguments are present, check that they correspond to a rest parameter. If so, no
5942
+ // further checking is necessary.
5943
+ var spreadArgIndex = getSpreadArgumentIndex(args);
5944
+ if (spreadArgIndex >= 0) {
5945
+ return signature.hasRestParameter && spreadArgIndex >= signature.parameters.length - 1;
5946
+ }
5893
5947
5894
- // If the call is incomplete, we should skip the lower bound check .
5895
- var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount;
5896
- return callIsIncomplete || hasEnoughArguments ;
5948
+ // Too many arguments implies incorrect arity .
5949
+ if (!signature.hasRestParameter && adjustedArgCount > signature.parameters.length) {
5950
+ return false ;
5897
5951
}
5952
+
5953
+ // If the call is incomplete, we should skip the lower bound check.
5954
+ var hasEnoughArguments = adjustedArgCount >= signature.minArgumentCount;
5955
+ return callIsIncomplete || hasEnoughArguments;
5898
5956
}
5899
5957
5900
5958
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
@@ -5927,32 +5985,32 @@ module ts {
5927
5985
// We perform two passes over the arguments. In the first pass we infer from all arguments, but use
5928
5986
// wildcards for all context sensitive function expressions.
5929
5987
for (var i = 0; i < args.length; i++) {
5930
- if (args[i].kind === SyntaxKind.OmittedExpression) {
5931
- continue;
5932
- }
5933
- var parameterType = getTypeAtPosition(signature, i);
5934
- if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) {
5935
- inferTypes(context, globalTemplateStringsArrayType, parameterType);
5936
- continue;
5988
+ var arg = args[i];
5989
+ if (arg.kind !== SyntaxKind.OmittedExpression) {
5990
+ var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
5991
+ if (i === 0 && args[i].parent.kind === SyntaxKind.TaggedTemplateExpression) {
5992
+ var argType = globalTemplateStringsArrayType;
5993
+ }
5994
+ else {
5995
+ // For context sensitive arguments we pass the identityMapper, which is a signal to treat all
5996
+ // context sensitive function expressions as wildcards
5997
+ var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper;
5998
+ var argType = checkExpressionWithContextualType(arg, paramType, mapper);
5999
+ }
6000
+ inferTypes(context, argType, paramType);
5937
6001
}
5938
- // For context sensitive arguments we pass the identityMapper, which is a signal to treat all
5939
- // context sensitive function expressions as wildcards
5940
- var mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : inferenceMapper;
5941
- inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, mapper), parameterType);
5942
6002
}
5943
6003
5944
6004
// In the second pass we visit only context sensitive arguments, and only those that aren't excluded, this
5945
6005
// time treating function expressions normally (which may cause previously inferred type arguments to be fixed
5946
6006
// as we construct types for contextually typed parameters)
5947
6007
if (excludeArgument) {
5948
6008
for (var i = 0; i < args.length; i++) {
5949
- if (args[i].kind === SyntaxKind.OmittedExpression) {
5950
- continue;
5951
- }
5952
- // No need to special-case tagged templates; their excludeArgument value will be 'undefined'.
6009
+ // No need to check for omitted args and template expressions, their exlusion value is always undefined
5953
6010
if (excludeArgument[i] === false) {
5954
- var parameterType = getTypeAtPosition(signature, i);
5955
- inferTypes(context, checkExpressionWithContextualType(args[i], parameterType, inferenceMapper), parameterType);
6011
+ var arg = args[i];
6012
+ var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
6013
+ inferTypes(context, checkExpressionWithContextualType(arg, paramType, inferenceMapper), paramType);
5956
6014
}
5957
6015
}
5958
6016
}
@@ -5990,37 +6048,24 @@ module ts {
5990
6048
return typeArgumentsAreAssignable;
5991
6049
}
5992
6050
5993
- function checkApplicableSignature(node: CallLikeExpression, args: Node [], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
6051
+ function checkApplicableSignature(node: CallLikeExpression, args: Expression [], signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[], reportErrors: boolean) {
5994
6052
for (var i = 0; i < args.length; i++) {
5995
6053
var arg = args[i];
5996
- var argType: Type;
5997
-
5998
- if (arg.kind === SyntaxKind.OmittedExpression) {
5999
- continue;
6000
- }
6001
-
6002
- var paramType = getTypeAtPosition(signature, i);
6003
-
6004
- if (i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression) {
6005
- // A tagged template expression has something of a
6006
- // "virtual" parameter with the "cooked" strings array type.
6007
- argType = globalTemplateStringsArrayType;
6008
- }
6009
- else {
6010
- // String literals get string literal types unless we're reporting errors
6011
- argType = arg.kind === SyntaxKind.StringLiteral && !reportErrors
6012
- ? getStringLiteralType(<LiteralExpression>arg)
6013
- : checkExpressionWithContextualType(<LiteralExpression>arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
6014
- }
6015
-
6016
- // Use argument expression as error location when reporting errors
6017
- var isValidArgument = checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
6018
- Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1);
6019
- if (!isValidArgument) {
6020
- return false;
6054
+ if (arg.kind !== SyntaxKind.OmittedExpression) {
6055
+ // Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter)
6056
+ var paramType = getTypeAtPosition(signature, arg.kind === SyntaxKind.SpreadElementExpression ? -1 : i);
6057
+ // A tagged template expression provides a special first argument, and string literals get string literal types
6058
+ // unless we're reporting errors
6059
+ var argType = i === 0 && node.kind === SyntaxKind.TaggedTemplateExpression ? globalTemplateStringsArrayType :
6060
+ arg.kind === SyntaxKind.StringLiteral && !reportErrors ? getStringLiteralType(<LiteralExpression>arg) :
6061
+ checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
6062
+ // Use argument expression as error location when reporting errors
6063
+ if (!checkTypeRelatedTo(argType, paramType, relation, reportErrors ? arg : undefined,
6064
+ Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1)) {
6065
+ return false;
6066
+ }
6021
6067
}
6022
6068
}
6023
-
6024
6069
return true;
6025
6070
}
6026
6071
@@ -6087,8 +6132,8 @@ module ts {
6087
6132
}
6088
6133
6089
6134
var candidates = candidatesOutArray || [];
6090
- // collectCandidates fills up the candidates array directly
6091
- collectCandidates( );
6135
+ // reorderCandidates fills up the candidates array directly
6136
+ reorderCandidates(signatures, candidates );
6092
6137
if (!candidates.length) {
6093
6138
error(node, Diagnostics.Supplied_parameters_do_not_match_any_signature_of_call_target);
6094
6139
return resolveErrorCall(node);
@@ -6278,60 +6323,6 @@ module ts {
6278
6323
return undefined;
6279
6324
}
6280
6325
6281
- // The candidate list orders groups in reverse, but within a group signatures are kept in declaration order
6282
- // A nit here is that we reorder only signatures that belong to the same symbol,
6283
- // so order how inherited signatures are processed is still preserved.
6284
- // interface A { (x: string): void }
6285
- // interface B extends A { (x: 'foo'): string }
6286
- // var b: B;
6287
- // b('foo') // <- here overloads should be processed as [(x:'foo'): string, (x: string): void]
6288
- function collectCandidates(): void {
6289
- var result = candidates;
6290
- var lastParent: Node;
6291
- var lastSymbol: Symbol;
6292
- var cutoffIndex: number = 0;
6293
- var index: number;
6294
- var specializedIndex: number = -1;
6295
- var spliceIndex: number;
6296
- Debug.assert(!result.length);
6297
- for (var i = 0; i < signatures.length; i++) {
6298
- var signature = signatures[i];
6299
- var symbol = signature.declaration && getSymbolOfNode(signature.declaration);
6300
- var parent = signature.declaration && signature.declaration.parent;
6301
- if (!lastSymbol || symbol === lastSymbol) {
6302
- if (lastParent && parent === lastParent) {
6303
- index++;
6304
- }
6305
- else {
6306
- lastParent = parent;
6307
- index = cutoffIndex;
6308
- }
6309
- }
6310
- else {
6311
- // current declaration belongs to a different symbol
6312
- // set cutoffIndex so re-orderings in the future won't change result set from 0 to cutoffIndex
6313
- index = cutoffIndex = result.length;
6314
- lastParent = parent;
6315
- }
6316
- lastSymbol = symbol;
6317
-
6318
- // specialized signatures always need to be placed before non-specialized signatures regardless
6319
- // of the cutoff position; see GH#1133
6320
- if (signature.hasStringLiterals) {
6321
- specializedIndex++;
6322
- spliceIndex = specializedIndex;
6323
- // The cutoff index always needs to be greater than or equal to the specialized signature index
6324
- // in order to prevent non-specialized signatures from being added before a specialized
6325
- // signature.
6326
- cutoffIndex++;
6327
- }
6328
- else {
6329
- spliceIndex = index;
6330
- }
6331
-
6332
- result.splice(spliceIndex, 0, signature);
6333
- }
6334
- }
6335
6326
}
6336
6327
6337
6328
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[]): Signature {
@@ -6387,6 +6378,13 @@ module ts {
6387
6378
}
6388
6379
6389
6380
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[]): Signature {
6381
+ if (node.arguments && languageVersion < ScriptTarget.ES6) {
6382
+ var spreadIndex = getSpreadArgumentIndex(node.arguments);
6383
+ if (spreadIndex >= 0) {
6384
+ error(node.arguments[spreadIndex], Diagnostics.Spread_operator_in_new_expressions_is_only_available_when_targeting_ECMAScript_6_and_higher);
6385
+ }
6386
+ }
6387
+
6390
6388
var expressionType = checkExpression(node.expression);
6391
6389
// TS 1.0 spec: 4.11
6392
6390
// If ConstructExpr is of type Any, Args can be any argument
@@ -6532,9 +6530,14 @@ module ts {
6532
6530
}
6533
6531
6534
6532
function getTypeAtPosition(signature: Signature, pos: number): Type {
6533
+ if (pos >= 0) {
6534
+ return signature.hasRestParameter ?
6535
+ pos < signature.parameters.length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
6536
+ pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType;
6537
+ }
6535
6538
return signature.hasRestParameter ?
6536
- pos < signature.parameters. length - 1 ? getTypeOfSymbol(signature.parameters[pos]) : getRestTypeOfSignature(signature ) :
6537
- pos < signature.parameters.length ? getTypeOfSymbol(signature.parameters[pos]) : anyType ;
6539
+ getTypeOfSymbol( signature.parameters[signature.parameters. length - 1] ) :
6540
+ anyArrayType ;
6538
6541
}
6539
6542
6540
6543
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
0 commit comments