@@ -4685,20 +4685,12 @@ namespace ts {
46854685 && lookAhead ( nextTokenIsIdentifierOrKeywordOrOpenBracketOrTemplate ) ;
46864686 }
46874687
4688- function hasOptionalChain ( node : Node ) {
4689- while ( true ) {
4690- if ( node . flags & NodeFlags . OptionalChain ) return true ;
4691- if ( ! isNonNullExpression ( node ) ) return false ;
4692- node = node . expression ;
4693- }
4694- }
4695-
46964688 function parsePropertyAccessExpressionRest ( expression : LeftHandSideExpression , questionDotToken : QuestionDotToken | undefined ) {
46974689 const propertyAccess = < PropertyAccessExpression > createNode ( SyntaxKind . PropertyAccessExpression , expression . pos ) ;
46984690 propertyAccess . expression = expression ;
46994691 propertyAccess . questionDotToken = questionDotToken ;
47004692 propertyAccess . name = parseRightSideOfDot ( /*allowIdentifierNames*/ true , /*allowPrivateIdentifiers*/ true ) ;
4701- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4693+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
47024694 propertyAccess . flags |= NodeFlags . OptionalChain ;
47034695 if ( isPrivateIdentifier ( propertyAccess . name ) ) {
47044696 parseErrorAtRange ( propertyAccess . name , Diagnostics . An_optional_chain_cannot_contain_private_identifiers ) ;
@@ -4724,12 +4716,43 @@ namespace ts {
47244716 }
47254717
47264718 parseExpected ( SyntaxKind . CloseBracketToken ) ;
4727- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4719+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
47284720 indexedAccess . flags |= NodeFlags . OptionalChain ;
47294721 }
47304722 return finishNode ( indexedAccess ) ;
47314723 }
47324724
4725+ function nextTokenContinuesOptionalChainAfterExclamationToken ( ) {
4726+ // consume a run of `!` tokens
4727+ while ( token ( ) === SyntaxKind . ExclamationToken && ! scanner . hasPrecedingLineBreak ( ) ) {
4728+ nextToken ( ) ;
4729+ }
4730+ switch ( token ( ) ) {
4731+ case SyntaxKind . DotToken :
4732+ case SyntaxKind . OpenBracketToken :
4733+ case SyntaxKind . OpenParenToken :
4734+ case SyntaxKind . NoSubstitutionTemplateLiteral :
4735+ case SyntaxKind . TemplateHead :
4736+ case SyntaxKind . QuestionDotToken :
4737+ // a?.b!.c
4738+ // a?.b![c]
4739+ // a?.b!()
4740+ // a?.b!`` (illegal syntax in javascript but we must parse it)
4741+ // a?.b!`${c}` (illegal syntax in javascript but we must parse it)
4742+ // a?.b!?.c
4743+ // a?.b!?.[c]
4744+ // a?.b!?.()
4745+ return true ;
4746+ case SyntaxKind . LessThanToken :
4747+ case SyntaxKind . LessThanLessThanToken :
4748+ // a?.b!<T>()
4749+ // a?.b!<<T>() (also handled in parseCallExpressionRest)
4750+ // look ahead to see if we are parsing a type argument list
4751+ return ! ! parseTypeArgumentsInExpression ( ) ;
4752+ }
4753+ return false ;
4754+ }
4755+
47334756 function parseMemberExpressionRest ( expression : LeftHandSideExpression , allowOptionalChain : boolean ) : MemberExpression {
47344757 while ( true ) {
47354758 let questionDotToken : QuestionDotToken | undefined ;
@@ -4751,6 +4774,9 @@ namespace ts {
47514774 nextToken ( ) ;
47524775 const nonNullExpression = < NonNullExpression > createNode ( SyntaxKind . NonNullExpression , expression . pos ) ;
47534776 nonNullExpression . expression = expression ;
4777+ if ( expression . flags & NodeFlags . OptionalChain && lookAhead ( nextTokenContinuesOptionalChainAfterExclamationToken ) ) {
4778+ nonNullExpression . flags |= NodeFlags . OptionalChain ;
4779+ }
47544780 expression = finishNode ( nonNullExpression ) ;
47554781 continue ;
47564782 }
@@ -4811,7 +4837,7 @@ namespace ts {
48114837 callExpr . questionDotToken = questionDotToken ;
48124838 callExpr . typeArguments = typeArguments ;
48134839 callExpr . arguments = parseArgumentList ( ) ;
4814- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4840+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
48154841 callExpr . flags |= NodeFlags . OptionalChain ;
48164842 }
48174843 expression = finishNode ( callExpr ) ;
@@ -4823,7 +4849,7 @@ namespace ts {
48234849 callExpr . expression = expression ;
48244850 callExpr . questionDotToken = questionDotToken ;
48254851 callExpr . arguments = parseArgumentList ( ) ;
4826- if ( questionDotToken || hasOptionalChain ( expression ) ) {
4852+ if ( questionDotToken || expression . flags & NodeFlags . OptionalChain ) {
48274853 callExpr . flags |= NodeFlags . OptionalChain ;
48284854 }
48294855 expression = finishNode ( callExpr ) ;
0 commit comments