@@ -3919,8 +3919,14 @@ ParseNodePtr Parser::ParsePostfixOperators(
39193919 {
39203920 AutoMarkInParsingArgs autoMarkInParsingArgs(this);
39213921
3922+ bool isNullPropagating = tkOptChain == this->GetScanner()->m_tkPrevious;
39223923 if (fInNew)
39233924 {
3925+ if (isNullPropagating)
3926+ {
3927+ Error(ERRInvalidOptChainInNew);
3928+ }
3929+
39243930 ParseNodePtr pnodeArgs = ParseArgList<buildAST>(&callOfConstants, &spreadArgCount, &count);
39253931 if (buildAST)
39263932 {
@@ -3973,6 +3979,11 @@ ParseNodePtr Parser::ParsePostfixOperators(
39733979 // Detect super()
39743980 if (this->NodeIsSuperName(pnode))
39753981 {
3982+ if (isNullPropagating)
3983+ {
3984+ Error(ERRInvalidOptChainInSuper);
3985+ }
3986+
39763987 pnode = CreateSuperCallNode(pnode->AsParseNodeSpecialName(), pnodeArgs);
39773988 Assert(pnode);
39783989
@@ -4007,6 +4018,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
40074018 pnode->AsParseNodeCall()->isApplyCall = false;
40084019 pnode->AsParseNodeCall()->isEvalCall = fCallIsEval;
40094020 pnode->AsParseNodeCall()->hasDestructuring = m_hasDestructuringPattern;
4021+ pnode->AsParseNodeCall()->isNullPropagating = isNullPropagating;
40104022 Assert(!m_hasDestructuringPattern || count > 0);
40114023 pnode->AsParseNodeCall()->argCount = count;
40124024 pnode->ichLim = this->GetScanner()->IchLimTok();
@@ -4042,7 +4054,7 @@ ParseNodePtr Parser::ParsePostfixOperators(
40424054 }
40434055 if (pfCanAssign)
40444056 {
4045- *pfCanAssign = fCanAssignToCallResult &&
4057+ *pfCanAssign = !isNullPropagating && fCanAssignToCallResult &&
40464058 (m_sourceContextInfo ?
40474059 !PHASE_ON_RAW(Js::EarlyErrorOnAssignToCallPhase, m_sourceContextInfo->sourceContextId, GetCurrentFunctionNode()->functionId) :
40484060 !PHASE_ON1(Js::EarlyErrorOnAssignToCallPhase));
@@ -4055,6 +4067,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
40554067 }
40564068 case tkLBrack:
40574069 {
4070+ bool isNullPropagating = tkOptChain == this->GetScanner()->m_tkPrevious;
4071+
40584072 this->GetScanner()->Scan();
40594073 IdentToken tok;
40604074 ParseNodePtr pnodeExpr = ParseExpr<buildAST>(0, FALSE, TRUE, FALSE, nullptr, nullptr, nullptr, &tok);
@@ -4063,12 +4077,17 @@ ParseNodePtr Parser::ParsePostfixOperators(
40634077 AnalysisAssert(pnodeExpr);
40644078 if (pnode && pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper)
40654079 {
4080+ if (isNullPropagating)
4081+ {
4082+ Error(ERRInvalidOptChainInSuper);
4083+ }
4084+
40664085 pnode = CreateSuperReferenceNode(knopIndex, pnode->AsParseNodeSpecialName(), pnodeExpr);
40674086 pnode->AsParseNodeSuperReference()->pnodeThis = ReferenceSpecialName(wellKnownPropertyPids._this, pnode->ichMin, pnode->ichLim, true);
40684087 }
40694088 else
40704089 {
4071- pnode = CreateBinNode(knopIndex, pnode, pnodeExpr);
4090+ pnode = CreateBinNode(knopIndex, pnode, pnodeExpr, isNullPropagating );
40724091 }
40734092
40744093 AnalysisAssert(pnode);
@@ -4082,7 +4101,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
40824101 ChkCurTok(tkRBrack, ERRnoRbrack);
40834102 if (pfCanAssign)
40844103 {
4085- *pfCanAssign = TRUE;
4104+ // optional assignment not permitted
4105+ *pfCanAssign = !isNullPropagating;
40864106 }
40874107 if (pfIsDotOrIndex)
40884108 {
@@ -4178,8 +4198,13 @@ ParseNodePtr Parser::ParsePostfixOperators(
41784198 this->GetScanner()->Scan();
41794199 if (!m_token.IsIdentifier())
41804200 {
4181- //allow reserved words in ES5 mode
4182- if (!(m_token.IsReservedWord()))
4201+ if (isNullPropagating && (tkLParen == m_token.tk || tkLBrack == m_token.tk))
4202+ {
4203+ // Continue to parse function or index (loop)
4204+ // Check previous token to check for null-propagation
4205+ continue;
4206+ }
4207+ else if (!(m_token.IsReservedWord())) //allow reserved words in ES5 mode
41834208 {
41844209 IdentifierExpectedError(m_token);
41854210 }
@@ -4206,6 +4231,11 @@ ParseNodePtr Parser::ParsePostfixOperators(
42064231 }
42074232 if (pnode && pnode->nop == knopName && pnode->AsParseNodeName()->IsSpecialName() && pnode->AsParseNodeSpecialName()->isSuper)
42084233 {
4234+ if (isNullPropagating)
4235+ {
4236+ Error(ERRInvalidOptChainInSuper);
4237+ }
4238+
42094239 pnode = CreateSuperReferenceNode(opCode, pnode->AsParseNodeSpecialName(), name);
42104240 pnode->AsParseNodeSuperReference()->pnodeThis = ReferenceSpecialName(wellKnownPropertyPids._this, pnode->ichMin, pnode->ichLim, true);
42114241 }
@@ -4222,7 +4252,8 @@ ParseNodePtr Parser::ParsePostfixOperators(
42224252
42234253 if (pfCanAssign)
42244254 {
4225- *pfCanAssign = TRUE;
4255+ // optional assignment not permitted
4256+ *pfCanAssign = !isNullPropagating;
42264257 }
42274258 if (pfIsDotOrIndex)
42284259 {
0 commit comments