@@ -180,7 +180,8 @@ namespace ts {
180180 visitNode ( cbNode , ( node as TypePredicateNode ) . parameterName ) ||
181181 visitNode ( cbNode , ( node as TypePredicateNode ) . type ) ;
182182 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 ) ;
184185 case SyntaxKind . TypeLiteral :
185186 return visitNodes ( cbNode , cbNodes , ( node as TypeLiteralNode ) . members ) ;
186187 case SyntaxKind . ArrayType :
@@ -3078,7 +3079,9 @@ namespace ts {
30783079 function parseTypeQuery ( ) : TypeQueryNode {
30793080 const pos = getNodePos ( ) ;
30803081 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 ) ;
30823085 }
30833086
30843087 function parseTypeParameter ( ) : TypeParameterDeclaration {
@@ -5428,23 +5431,33 @@ namespace ts {
54285431 continue ;
54295432 }
54305433
5431- if ( ! questionDotToken && token ( ) === SyntaxKind . ExclamationToken && ! scanner . hasPrecedingLineBreak ( ) ) {
5432- nextToken ( ) ;
5433- expression = finishNode ( factory . createNonNullExpression ( expression ) , pos ) ;
5434- continue ;
5435- }
5436-
54375434 // when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
54385435 if ( ( questionDotToken || ! inDecoratorContext ( ) ) && parseOptional ( SyntaxKind . OpenBracketToken ) ) {
54395436 expression = parseElementAccessExpressionRest ( pos , expression , questionDotToken ) ;
54405437 continue ;
54415438 }
54425439
54435440 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 ) ;
54455445 continue ;
54465446 }
54475447
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+
54485461 return expression as MemberExpression ;
54495462 }
54505463 }
@@ -5471,39 +5484,30 @@ namespace ts {
54715484 function parseCallExpressionRest ( pos : number , expression : LeftHandSideExpression ) : LeftHandSideExpression {
54725485 while ( true ) {
54735486 expression = parseMemberExpressionRest ( pos , expression , /*allowOptionalChain*/ true ) ;
5487+ let typeArguments : NodeArray < TypeNode > | undefined ;
54745488 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 ) ;
54945493 continue ;
54955494 }
54965495 }
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+ }
54985502 const argumentList = parseArgumentList ( ) ;
54995503 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 ) ;
55025506 expression = finishNode ( callExpr , pos ) ;
55035507 continue ;
55045508 }
55055509 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.
55075511 const name = createMissingNode < Identifier > ( SyntaxKind . Identifier , /*reportAtCurrentPosition*/ false , Diagnostics . Identifier_expected ) ;
55085512 expression = finishNode ( factory . createPropertyAccessChain ( expression , questionDotToken , name ) , pos ) ;
55095513 }
@@ -5536,22 +5540,26 @@ namespace ts {
55365540 return undefined ;
55375541 }
55385542
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 ;
55445548 }
55455549
55465550 function canFollowTypeArgumentsInExpression ( ) : boolean {
55475551 switch ( token ( ) ) {
5552+ // These tokens can follow a type argument list in a call expression.
55485553 case SyntaxKind . OpenParenToken : // foo<x>(
55495554 case SyntaxKind . NoSubstitutionTemplateLiteral : // foo<T> `...`
55505555 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.
55535559 // falls through
5560+ case SyntaxKind . CommaToken : // foo<x>,
55545561 case SyntaxKind . DotToken : // foo<x>.
5562+ case SyntaxKind . QuestionDotToken : // foo<x>?.
55555563 case SyntaxKind . CloseParenToken : // foo<x>)
55565564 case SyntaxKind . CloseBracketToken : // foo<x>]
55575565 case SyntaxKind . ColonToken : // foo<x>:
@@ -5569,21 +5577,10 @@ namespace ts {
55695577 case SyntaxKind . BarToken : // foo<x> |
55705578 case SyntaxKind . CloseBraceToken : // foo<x> }
55715579 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.
55755580 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 ;
55865581 }
5582+ // Treat anything else as an expression.
5583+ return false ;
55875584 }
55885585
55895586 function parsePrimaryExpression ( ) : PrimaryExpression {
@@ -5790,30 +5787,16 @@ namespace ts {
57905787 const name = parseIdentifierName ( ) ;
57915788 return finishNode ( factory . createMetaProperty ( SyntaxKind . NewKeyword , name ) , pos ) ;
57925789 }
5793-
57945790 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 ;
58075797 }
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 ) ;
58175800 }
58185801
58195802 // STATEMENTS
@@ -7071,6 +7054,9 @@ namespace ts {
70717054 function parseExpressionWithTypeArguments ( ) : ExpressionWithTypeArguments {
70727055 const pos = getNodePos ( ) ;
70737056 const expression = parseLeftHandSideExpressionOrHigher ( ) ;
7057+ if ( expression . kind === SyntaxKind . ExpressionWithTypeArguments ) {
7058+ return expression as ExpressionWithTypeArguments ;
7059+ }
70747060 const typeArguments = tryParseTypeArguments ( ) ;
70757061 return finishNode ( factory . createExpressionWithTypeArguments ( expression , typeArguments ) , pos ) ;
70767062 }
0 commit comments