6
6
/// <reference path="emitter.ts"/>
7
7
8
8
module ts {
9
-
10
9
var nextSymbolId = 1 ;
11
10
var nextNodeId = 1 ;
12
11
var nextMergeId = 1 ;
@@ -57,6 +56,8 @@ module ts {
57
56
return stringWriters . pop ( ) ;
58
57
}
59
58
59
+ type CallLikeExpression = CallExpression | TaggedTemplateExpression ;
60
+
60
61
/// fullTypeCheck denotes if this instance of the typechecker will be used to get semantic diagnostics.
61
62
/// If fullTypeCheck === true, then the typechecker should do every possible check to produce all errors
62
63
/// If fullTypeCheck === false, the typechecker can take shortcuts and skip checks that only produce errors.
@@ -5183,7 +5184,7 @@ module ts {
5183
5184
return unknownType ;
5184
5185
}
5185
5186
5186
- function resolveUntypedCall ( node : CallExpression | TaggedTemplateExpression ) : Signature {
5187
+ function resolveUntypedCall ( node : CallLikeExpression ) : Signature {
5187
5188
if ( node . kind === SyntaxKind . TaggedTemplateExpression ) {
5188
5189
checkExpression ( ( < TaggedTemplateExpression > node ) . template ) ;
5189
5190
}
@@ -5195,52 +5196,78 @@ module ts {
5195
5196
return anySignature ;
5196
5197
}
5197
5198
5198
- function resolveErrorCall ( node : CallExpression | TaggedTemplateExpression ) : Signature {
5199
+ function resolveErrorCall ( node : CallLikeExpression ) : Signature {
5199
5200
resolveUntypedCall ( node ) ;
5200
5201
return unknownSignature ;
5201
5202
}
5202
5203
5203
- function signatureHasCorrectArity ( node : CallExpression | TaggedTemplateExpression , args : Expression [ ] , signature : Signature ) : boolean {
5204
- var isTaggedTemplate = node . kind === SyntaxKind . TaggedTemplateExpression ;
5204
+ function hasCorrectArity ( node : CallLikeExpression , args : Expression [ ] , signature : Signature ) {
5205
+ var adjustedArgCount : number ;
5206
+ var typeArguments : NodeArray < TypeNode > ;
5207
+ var callIsIncomplete = false ;
5205
5208
5206
- if ( ! isTaggedTemplate && ! ( < CallExpression > node ) . arguments ) {
5207
- // This only happens when we have something of the form:
5208
- // new C
5209
- //
5210
- Debug . assert ( node . kind === SyntaxKind . NewExpression ) ;
5211
- return signature . minArgumentCount === 0 ;
5212
- }
5213
-
5214
- // For IDE scenarios, since we may have an incomplete call, we make two modifications
5215
- // to arity checking.
5216
- // 1. A trailing comma is tantamount to adding another argument
5217
- // 2. If the call is incomplete (no closing paren) allow fewer arguments than expected
5218
- var numberOfArgs = ! isTaggedTemplate && ( < CallExpression > node ) . arguments . hasTrailingComma
5219
- ? args . length + 1
5220
- : args . length ;
5221
- var hasTooManyArguments = ! signature . hasRestParameter && numberOfArgs > signature . parameters . length ;
5222
- var hasRightNumberOfTypeArguments = ! ( < CallExpression > node ) . typeArguments ||
5223
- ( signature . typeParameters && ( < CallExpression > node ) . typeArguments . length === signature . typeParameters . length ) ;
5224
-
5225
- if ( hasTooManyArguments || ! hasRightNumberOfTypeArguments ) {
5226
- return false ;
5227
- }
5209
+ if ( node . kind === SyntaxKind . TaggedTemplateExpression ) {
5210
+ var tagExpression = < TaggedTemplateExpression > node ;
5228
5211
5229
- // If we are missing the close paren, the call is incomplete, and we should skip
5230
- // the lower bound check.
5231
- var callIsIncomplete = false ;
5232
- if ( isTaggedTemplate ) {
5233
- var template = ( < TaggedTemplateExpression > node ) . template ;
5234
- if ( template . kind === SyntaxKind . TemplateExpression ) {
5235
- var lastSpan = lastOrUndefined ( ( < TemplateExpression > template ) . templateSpans )
5212
+ adjustedArgCount = args . length ;
5213
+ typeArguments = undefined ;
5214
+
5215
+ if ( tagExpression . kind === SyntaxKind . TemplateExpression ) {
5216
+ // If a tagged template expression lacks a tail literal, the call is incomplete.
5217
+ var template = < TemplateExpression > tagExpression . template ;
5218
+ var lastSpan = lastOrUndefined ( template . templateSpans ) ;
5219
+ Debug . assert ( lastSpan !== undefined ) ; // we should always have at least one span.
5236
5220
callIsIncomplete = lastSpan === undefined || lastSpan . literal . kind !== SyntaxKind . TemplateTail ;
5237
5221
}
5238
5222
}
5239
5223
else {
5240
- callIsIncomplete = ( < CallExpression > node ) . arguments . end === node . end ;
5224
+ var callExpression = < CallExpression > node ;
5225
+ if ( ! callExpression . arguments ) {
5226
+ // This only happens when we have something of the form: 'new C'
5227
+ Debug . assert ( callExpression . kind === SyntaxKind . NewExpression ) ;
5228
+
5229
+ return signature . minArgumentCount === 0 ;
5230
+ }
5231
+ else {
5232
+ // For IDE scenarios we may have an incomplete call, so a trailing comma is tantamount to adding another argument.
5233
+ adjustedArgCount = callExpression . arguments . hasTrailingComma ? args . length + 1 : args . length ;
5234
+
5235
+ // If we are missing the close paren, the call is incomplete.
5236
+ callIsIncomplete = ( < CallExpression > callExpression ) . arguments . end === callExpression . end ;
5237
+ }
5238
+
5239
+ typeArguments = callExpression . typeArguments ;
5240
+ }
5241
+
5242
+ return checkArity ( adjustedArgCount , typeArguments , callIsIncomplete , signature ) ;
5243
+
5244
+ /**
5245
+ * @param adjustedArgCount The "apparent" number of arguments that we will have in this call.
5246
+ * @param typeArguments Type arguments node of the call if it exists; undefined otherwise.
5247
+ * @param callIsIncomplete Whether or not a call is unfinished, and we should be "lenient" when we have too few arguments.
5248
+ * @param signature The signature whose arity we are comparing.
5249
+ */
5250
+ function checkArity ( adjustedArgCount : number ,
5251
+ typeArguments : NodeArray < TypeNode > ,
5252
+ callIsIncomplete : boolean ,
5253
+ signature : Signature ) : boolean {
5254
+ // Too many arguments implies incorrect arity.
5255
+ if ( ! signature . hasRestParameter && adjustedArgCount > signature . parameters . length ) {
5256
+ return false ;
5257
+ }
5258
+
5259
+ // If the user supplied type arguments, but the number of type arguments does not match
5260
+ // the declared number of type parameters, the call has an incorrect arity.
5261
+ var hasRightNumberOfTypeArgs = ! typeArguments ||
5262
+ ( signature . typeParameters && typeArguments . length === signature . typeParameters . length ) ;
5263
+ if ( ! hasRightNumberOfTypeArgs ) {
5264
+ return false ;
5265
+ }
5266
+
5267
+ // If the call is incomplete, we should skip the lower bound check.
5268
+ var hasEnoughArguments = adjustedArgCount >= signature . minArgumentCount ;
5269
+ return callIsIncomplete || hasEnoughArguments ;
5241
5270
}
5242
- var hasEnoughArguments = numberOfArgs >= signature . minArgumentCount ;
5243
- return callIsIncomplete || hasEnoughArguments ;
5244
5271
}
5245
5272
5246
5273
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
@@ -5332,7 +5359,7 @@ module ts {
5332
5359
return typeArgumentsAreAssignable ;
5333
5360
}
5334
5361
5335
- function checkApplicableSignature ( node : CallExpression | TaggedTemplateExpression , args : Node [ ] , signature : Signature , relation : Map < Ternary > , excludeArgument : boolean [ ] , reportErrors : boolean ) {
5362
+ function checkApplicableSignature ( node : CallLikeExpression , args : Node [ ] , signature : Signature , relation : Map < Ternary > , excludeArgument : boolean [ ] , reportErrors : boolean ) {
5336
5363
for ( var i = 0 ; i < args . length ; i ++ ) {
5337
5364
var arg = args [ i ] ;
5338
5365
var argType : Type ;
@@ -5371,16 +5398,18 @@ module ts {
5371
5398
*
5372
5399
* If 'node' is a CallExpression or a NewExpression, then its argument list is returned.
5373
5400
* If 'node' is a TaggedTemplateExpression, a new argument list is constructed from the substitution
5374
- * expressions, where the first element of the argument list is the template portion for error reporting purposes.
5401
+ * expressions, where the first element of the list is the template for error reporting purposes.
5375
5402
*/
5376
- function getEffectiveCallArguments ( node : CallExpression | TaggedTemplateExpression ) : Expression [ ] {
5403
+ function getEffectiveCallArguments ( node : CallLikeExpression ) : Expression [ ] {
5377
5404
var args : Expression [ ] ;
5378
5405
if ( node . kind === SyntaxKind . TaggedTemplateExpression ) {
5379
5406
var template = ( < TaggedTemplateExpression > node ) . template ;
5380
5407
args = [ template ] ;
5381
5408
5382
5409
if ( template . kind === SyntaxKind . TemplateExpression ) {
5383
- args . push . apply ( args , map ( ( < TemplateExpression > template ) . templateSpans , span => span . expression ) ) ;
5410
+ forEach ( ( < TemplateExpression > template ) . templateSpans , span => {
5411
+ args . push ( span . expression ) ;
5412
+ } ) ;
5384
5413
}
5385
5414
}
5386
5415
else {
@@ -5390,7 +5419,7 @@ module ts {
5390
5419
return args ;
5391
5420
}
5392
5421
5393
- function resolveCall ( node : CallExpression | TaggedTemplateExpression , signatures : Signature [ ] , candidatesOutArray : Signature [ ] ) : Signature {
5422
+ function resolveCall ( node : CallLikeExpression , signatures : Signature [ ] , candidatesOutArray : Signature [ ] ) : Signature {
5394
5423
var typeArguments = ( < CallExpression > node ) . typeArguments ;
5395
5424
forEach ( typeArguments , checkSourceElement ) ;
5396
5425
@@ -5410,7 +5439,12 @@ module ts {
5410
5439
// - undefined: the argument at 'i' is *not* susceptible to permanent contextual typing.
5411
5440
// - false: the argument at 'i' *was* and *has been* permanently contextually typed.
5412
5441
//
5413
- // If the expression is a tagged template, then the first argument is implicitly the "cooked" strings array.
5442
+ // The idea is that we will perform type argument inference & assignability checking once
5443
+ // without using the susceptible parameters, and once more for each susceptible parameter,
5444
+ // contextually typing each as we go along.
5445
+ //
5446
+ // For a tagged template, then the first argument be 'undefined' if necessary
5447
+ // because it represents a TemplateStringsArray.
5414
5448
var excludeArgument : boolean [ ] ;
5415
5449
for ( var i = isTaggedTemplate ? 1 : 0 ; i < args . length ; i ++ ) {
5416
5450
if ( isContextSensitiveExpression ( args [ i ] ) ) {
@@ -5484,7 +5518,7 @@ module ts {
5484
5518
checkApplicableSignature ( node , args , candidateForArgumentError , assignableRelation , /*excludeArgument*/ undefined , /*reportErrors*/ true ) ;
5485
5519
}
5486
5520
else if ( candidateForTypeArgumentError ) {
5487
- if ( ( < CallExpression > node ) . typeArguments ) {
5521
+ if ( ! isTaggedTemplate && ( < CallExpression > node ) . typeArguments ) {
5488
5522
checkTypeArguments ( candidateForTypeArgumentError , ( < CallExpression > node ) . typeArguments , [ ] , /*reportErrors*/ true )
5489
5523
}
5490
5524
else {
@@ -5510,7 +5544,7 @@ module ts {
5510
5544
// f({ |
5511
5545
if ( ! fullTypeCheck ) {
5512
5546
for ( var i = 0 , n = candidates . length ; i < n ; i ++ ) {
5513
- if ( signatureHasCorrectArity ( node , args , candidates [ i ] ) ) {
5547
+ if ( hasCorrectArity ( node , args , candidates [ i ] ) ) {
5514
5548
return candidates [ i ] ;
5515
5549
}
5516
5550
}
@@ -5520,7 +5554,7 @@ module ts {
5520
5554
5521
5555
function chooseOverload ( candidates : Signature [ ] , relation : Map < Ternary > , excludeArgument : boolean [ ] ) {
5522
5556
for ( var i = 0 ; i < candidates . length ; i ++ ) {
5523
- if ( ! signatureHasCorrectArity ( node , args , candidates [ i ] ) ) {
5557
+ if ( ! hasCorrectArity ( node , args , candidates [ i ] ) ) {
5524
5558
continue ;
5525
5559
}
5526
5560
@@ -5751,7 +5785,7 @@ module ts {
5751
5785
5752
5786
// candidatesOutArray is passed by signature help in the language service, and collectCandidates
5753
5787
// must fill it up with the appropriate candidate signatures
5754
- function getResolvedSignature ( node : CallExpression | TaggedTemplateExpression , candidatesOutArray ?: Signature [ ] ) : Signature {
5788
+ function getResolvedSignature ( node : CallLikeExpression , candidatesOutArray ?: Signature [ ] ) : Signature {
5755
5789
var links = getNodeLinks ( node ) ;
5756
5790
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
5757
5791
// However, it is possible that either candidatesOutArray was not passed in the first time,
0 commit comments