@@ -180,7 +180,8 @@ namespace ts {
180
180
visitNode ( cbNode , ( node as TypePredicateNode ) . parameterName ) ||
181
181
visitNode ( cbNode , ( node as TypePredicateNode ) . type ) ;
182
182
case SyntaxKind . TypeQuery :
183
- return visitNode ( cbNode , ( node as TypeQueryNode ) . exprName ) ;
183
+ return visitNode ( cbNode , ( node as TypeQueryNode ) . exprName ) ||
184
+ visitNodes ( cbNode , cbNodes , ( node as TypeQueryNode ) . typeArguments ) ;
184
185
case SyntaxKind . TypeLiteral :
185
186
return visitNodes ( cbNode , cbNodes , ( node as TypeLiteralNode ) . members ) ;
186
187
case SyntaxKind . ArrayType :
@@ -3078,7 +3079,9 @@ namespace ts {
3078
3079
function parseTypeQuery ( ) : TypeQueryNode {
3079
3080
const pos = getNodePos ( ) ;
3080
3081
parseExpected ( SyntaxKind . TypeOfKeyword ) ;
3081
- return finishNode ( factory . createTypeQueryNode ( parseEntityName ( /*allowReservedWords*/ true , /*allowPrivateIdentifiers*/ true ) ) , pos ) ;
3082
+ const entityName = parseEntityName ( /*allowReservedWords*/ true , /*allowPrivateIdentifiers*/ true ) ;
3083
+ const typeArguments = tryParseTypeArguments ( ) ;
3084
+ return finishNode ( factory . createTypeQueryNode ( entityName , typeArguments ) , pos ) ;
3082
3085
}
3083
3086
3084
3087
function parseTypeParameter ( ) : TypeParameterDeclaration {
@@ -5428,23 +5431,33 @@ namespace ts {
5428
5431
continue ;
5429
5432
}
5430
5433
5431
- if ( ! questionDotToken && token ( ) === SyntaxKind . ExclamationToken && ! scanner . hasPrecedingLineBreak ( ) ) {
5432
- nextToken ( ) ;
5433
- expression = finishNode ( factory . createNonNullExpression ( expression ) , pos ) ;
5434
- continue ;
5435
- }
5436
-
5437
5434
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
5438
5435
if ( ( questionDotToken || ! inDecoratorContext ( ) ) && parseOptional ( SyntaxKind . OpenBracketToken ) ) {
5439
5436
expression = parseElementAccessExpressionRest ( pos , expression , questionDotToken ) ;
5440
5437
continue ;
5441
5438
}
5442
5439
5443
5440
if ( isTemplateStartOfTaggedTemplate ( ) ) {
5444
- expression = parseTaggedTemplateRest ( pos , expression , questionDotToken , /*typeArguments*/ undefined ) ;
5441
+ // Absorb type arguments into TemplateExpression when preceding expression is ExpressionWithTypeArguments
5442
+ expression = ! questionDotToken && expression . kind === SyntaxKind . ExpressionWithTypeArguments ?
5443
+ parseTaggedTemplateRest ( pos , ( expression as ExpressionWithTypeArguments ) . expression , questionDotToken , ( expression as ExpressionWithTypeArguments ) . typeArguments ) :
5444
+ parseTaggedTemplateRest ( pos , expression , questionDotToken , /*typeArguments*/ undefined ) ;
5445
5445
continue ;
5446
5446
}
5447
5447
5448
+ if ( ! questionDotToken ) {
5449
+ if ( token ( ) === SyntaxKind . ExclamationToken && ! scanner . hasPrecedingLineBreak ( ) ) {
5450
+ nextToken ( ) ;
5451
+ expression = finishNode ( factory . createNonNullExpression ( expression ) , pos ) ;
5452
+ continue ;
5453
+ }
5454
+ const typeArguments = tryParse ( parseTypeArgumentsInExpression ) ;
5455
+ if ( typeArguments ) {
5456
+ expression = finishNode ( factory . createExpressionWithTypeArguments ( expression , typeArguments ) , pos ) ;
5457
+ continue ;
5458
+ }
5459
+ }
5460
+
5448
5461
return expression as MemberExpression ;
5449
5462
}
5450
5463
}
@@ -5471,39 +5484,30 @@ namespace ts {
5471
5484
function parseCallExpressionRest ( pos : number , expression : LeftHandSideExpression ) : LeftHandSideExpression {
5472
5485
while ( true ) {
5473
5486
expression = parseMemberExpressionRest ( pos , expression , /*allowOptionalChain*/ true ) ;
5487
+ let typeArguments : NodeArray < TypeNode > | undefined ;
5474
5488
const questionDotToken = parseOptionalToken ( SyntaxKind . QuestionDotToken ) ;
5475
- // handle 'foo<<T>()'
5476
- // parse template arguments only in TypeScript files (not in JavaScript files).
5477
- if ( ( contextFlags & NodeFlags . JavaScriptFile ) === 0 && ( token ( ) === SyntaxKind . LessThanToken || token ( ) === SyntaxKind . LessThanLessThanToken ) ) {
5478
- // See if this is the start of a generic invocation. If so, consume it and
5479
- // keep checking for postfix expressions. Otherwise, it's just a '<' that's
5480
- // part of an arithmetic expression. Break out so we consume it higher in the
5481
- // stack.
5482
- const typeArguments = tryParse ( parseTypeArgumentsInExpression ) ;
5483
- if ( typeArguments ) {
5484
- if ( isTemplateStartOfTaggedTemplate ( ) ) {
5485
- expression = parseTaggedTemplateRest ( pos , expression , questionDotToken , typeArguments ) ;
5486
- continue ;
5487
- }
5488
-
5489
- const argumentList = parseArgumentList ( ) ;
5490
- const callExpr = questionDotToken || tryReparseOptionalChain ( expression ) ?
5491
- factory . createCallChain ( expression , questionDotToken , typeArguments , argumentList ) :
5492
- factory . createCallExpression ( expression , typeArguments , argumentList ) ;
5493
- expression = finishNode ( callExpr , pos ) ;
5489
+ if ( questionDotToken ) {
5490
+ typeArguments = tryParse ( parseTypeArgumentsInExpression ) ;
5491
+ if ( isTemplateStartOfTaggedTemplate ( ) ) {
5492
+ expression = parseTaggedTemplateRest ( pos , expression , questionDotToken , typeArguments ) ;
5494
5493
continue ;
5495
5494
}
5496
5495
}
5497
- else if ( token ( ) === SyntaxKind . OpenParenToken ) {
5496
+ if ( typeArguments || token ( ) === SyntaxKind . OpenParenToken ) {
5497
+ // Absorb type arguments into CallExpression when preceding expression is ExpressionWithTypeArguments
5498
+ if ( ! questionDotToken && expression . kind === SyntaxKind . ExpressionWithTypeArguments ) {
5499
+ typeArguments = ( expression as ExpressionWithTypeArguments ) . typeArguments ;
5500
+ expression = ( expression as ExpressionWithTypeArguments ) . expression ;
5501
+ }
5498
5502
const argumentList = parseArgumentList ( ) ;
5499
5503
const callExpr = questionDotToken || tryReparseOptionalChain ( expression ) ?
5500
- factory . createCallChain ( expression , questionDotToken , /* typeArguments*/ undefined , argumentList ) :
5501
- factory . createCallExpression ( expression , /* typeArguments*/ undefined , argumentList ) ;
5504
+ factory . createCallChain ( expression , questionDotToken , typeArguments , argumentList ) :
5505
+ factory . createCallExpression ( expression , typeArguments , argumentList ) ;
5502
5506
expression = finishNode ( callExpr , pos ) ;
5503
5507
continue ;
5504
5508
}
5505
5509
if ( questionDotToken ) {
5506
- // We failed to parse anything, so report a missing identifier here.
5510
+ // We parsed `?.` but then failed to parse anything, so report a missing identifier here.
5507
5511
const name = createMissingNode < Identifier > ( SyntaxKind . Identifier , /*reportAtCurrentPosition*/ false , Diagnostics . Identifier_expected ) ;
5508
5512
expression = finishNode ( factory . createPropertyAccessChain ( expression , questionDotToken , name ) , pos ) ;
5509
5513
}
@@ -5536,22 +5540,26 @@ namespace ts {
5536
5540
return undefined ;
5537
5541
}
5538
5542
5539
- // If we have a '<', then only parse this as a argument list if the type arguments
5540
- // are complete and we have an open paren. if we don't, rewind and return nothing.
5541
- return typeArguments && canFollowTypeArgumentsInExpression ( )
5542
- ? typeArguments
5543
- : undefined ;
5543
+ // We successfully parsed a type argument list. The next token determines whether we want to
5544
+ // treat it as such. If the type argument list is followed by `(` or a template literal, as in
5545
+ // `f<number>(42)`, we favor the type argument interpretation even though JavaScript would view
5546
+ // it as a relational expression.
5547
+ return typeArguments && canFollowTypeArgumentsInExpression ( ) ? typeArguments : undefined ;
5544
5548
}
5545
5549
5546
5550
function canFollowTypeArgumentsInExpression ( ) : boolean {
5547
5551
switch ( token ( ) ) {
5552
+ // These tokens can follow a type argument list in a call expression.
5548
5553
case SyntaxKind . OpenParenToken : // foo<x>(
5549
5554
case SyntaxKind . NoSubstitutionTemplateLiteral : // foo<T> `...`
5550
5555
case SyntaxKind . TemplateHead : // foo<T> `...${100}...`
5551
- // these are the only tokens can legally follow a type argument
5552
- // list. So we definitely want to treat them as type arg lists.
5556
+ // These tokens can't follow in a call expression, nor can they start an
5557
+ // expression. So, consider the type argument list part of an instantiation
5558
+ // expression.
5553
5559
// falls through
5560
+ case SyntaxKind . CommaToken : // foo<x>,
5554
5561
case SyntaxKind . DotToken : // foo<x>.
5562
+ case SyntaxKind . QuestionDotToken : // foo<x>?.
5555
5563
case SyntaxKind . CloseParenToken : // foo<x>)
5556
5564
case SyntaxKind . CloseBracketToken : // foo<x>]
5557
5565
case SyntaxKind . ColonToken : // foo<x>:
@@ -5569,21 +5577,10 @@ namespace ts {
5569
5577
case SyntaxKind . BarToken : // foo<x> |
5570
5578
case SyntaxKind . CloseBraceToken : // foo<x> }
5571
5579
case SyntaxKind . EndOfFileToken : // foo<x>
5572
- // these cases can't legally follow a type arg list. However, they're not legal
5573
- // expressions either. The user is probably in the middle of a generic type. So
5574
- // treat it as such.
5575
5580
return true ;
5576
-
5577
- case SyntaxKind . CommaToken : // foo<x>,
5578
- case SyntaxKind . OpenBraceToken : // foo<x> {
5579
- // We don't want to treat these as type arguments. Otherwise we'll parse this
5580
- // as an invocation expression. Instead, we want to parse out the expression
5581
- // in isolation from the type arguments.
5582
- // falls through
5583
- default :
5584
- // Anything else treat as an expression.
5585
- return false ;
5586
5581
}
5582
+ // Treat anything else as an expression.
5583
+ return false ;
5587
5584
}
5588
5585
5589
5586
function parsePrimaryExpression ( ) : PrimaryExpression {
@@ -5790,30 +5787,16 @@ namespace ts {
5790
5787
const name = parseIdentifierName ( ) ;
5791
5788
return finishNode ( factory . createMetaProperty ( SyntaxKind . NewKeyword , name ) , pos ) ;
5792
5789
}
5793
-
5794
5790
const expressionPos = getNodePos ( ) ;
5795
- let expression : MemberExpression = parsePrimaryExpression ( ) ;
5796
- let typeArguments ;
5797
- while ( true ) {
5798
- expression = parseMemberExpressionRest ( expressionPos , expression , /*allowOptionalChain*/ false ) ;
5799
- typeArguments = tryParse ( parseTypeArgumentsInExpression ) ;
5800
- if ( isTemplateStartOfTaggedTemplate ( ) ) {
5801
- Debug . assert ( ! ! typeArguments ,
5802
- "Expected a type argument list; all plain tagged template starts should be consumed in 'parseMemberExpressionRest'" ) ;
5803
- expression = parseTaggedTemplateRest ( expressionPos , expression , /*optionalChain*/ undefined , typeArguments ) ;
5804
- typeArguments = undefined ;
5805
- }
5806
- break ;
5791
+ let expression : LeftHandSideExpression = parseMemberExpressionRest ( expressionPos , parsePrimaryExpression ( ) , /*allowOptionalChain*/ false ) ;
5792
+ let typeArguments : NodeArray < TypeNode > | undefined ;
5793
+ // Absorb type arguments into NewExpression when preceding expression is ExpressionWithTypeArguments
5794
+ if ( expression . kind === SyntaxKind . ExpressionWithTypeArguments ) {
5795
+ typeArguments = ( expression as ExpressionWithTypeArguments ) . typeArguments ;
5796
+ expression = ( expression as ExpressionWithTypeArguments ) . expression ;
5807
5797
}
5808
-
5809
- let argumentsArray : NodeArray < Expression > | undefined ;
5810
- if ( token ( ) === SyntaxKind . OpenParenToken ) {
5811
- argumentsArray = parseArgumentList ( ) ;
5812
- }
5813
- else if ( typeArguments ) {
5814
- parseErrorAt ( pos , scanner . getStartPos ( ) , Diagnostics . A_new_expression_with_type_arguments_must_always_be_followed_by_a_parenthesized_argument_list ) ;
5815
- }
5816
- return finishNode ( factory . createNewExpression ( expression , typeArguments , argumentsArray ) , pos ) ;
5798
+ const argumentList = token ( ) === SyntaxKind . OpenParenToken ? parseArgumentList ( ) : undefined ;
5799
+ return finishNode ( factory . createNewExpression ( expression , typeArguments , argumentList ) , pos ) ;
5817
5800
}
5818
5801
5819
5802
// STATEMENTS
@@ -7071,6 +7054,9 @@ namespace ts {
7071
7054
function parseExpressionWithTypeArguments ( ) : ExpressionWithTypeArguments {
7072
7055
const pos = getNodePos ( ) ;
7073
7056
const expression = parseLeftHandSideExpressionOrHigher ( ) ;
7057
+ if ( expression . kind === SyntaxKind . ExpressionWithTypeArguments ) {
7058
+ return expression as ExpressionWithTypeArguments ;
7059
+ }
7074
7060
const typeArguments = tryParseTypeArguments ( ) ;
7075
7061
return finishNode ( factory . createExpressionWithTypeArguments ( expression , typeArguments ) , pos ) ;
7076
7062
}
0 commit comments