diff --git a/lib/Parser/Parse.cpp b/lib/Parser/Parse.cpp index 5af49c60664..25247932118 100644 --- a/lib/Parser/Parse.cpp +++ b/lib/Parser/Parse.cpp @@ -1632,7 +1632,7 @@ ParseNodePtr Parser::ParseBlock(ParseNodePtr pnodeLabel, LabelId* pLabelId) && outerBlockInfo->pnodeBlock->sxBlock.scope != nullptr && outerBlockInfo->pnodeBlock->sxBlock.scope->GetScopeType() == ScopeType_CatchParamPattern) { - // If we are parsing the catch block then destructured params can have let declrations. Let's add them to the new block. + // If we are parsing the catch block then destructured params can have let declarations. Let's add them to the new block. for (ParseNodePtr pnode = m_currentBlockInfo->pBlockInfoOuter->pnodeBlock->sxBlock.pnodeLexVars; pnode; pnode = pnode->sxVar.pnodeNext) { PidRefStack* ref = PushPidRef(pnode->sxVar.sym->GetPid()); @@ -1659,7 +1659,6 @@ ParseNodePtr Parser::ParseBlock(ParseNodePtr pnodeLabel, LabelId* pLabelId) ChkCurTok(tkRCurly, ERRnoRcurly); - return pnodeBlock; } @@ -5130,8 +5129,9 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool pnodeFnc->sxFnc.SetIsClassConstructor((flags & fFncClassConstructor) != 0); pnodeFnc->sxFnc.SetIsBaseClassConstructor((flags & fFncBaseClassConstructor) != 0); + IdentPtr pFncNamePid = nullptr; bool needScanRCurly = true; - bool result = ParseFncDeclHelper(pnodeFnc, pNameHint, flags, &funcHasName, fUnaryOrParen, noStmtContext, &needScanRCurly, fModule); + bool result = ParseFncDeclHelper(pnodeFnc, pNameHint, flags, &funcHasName, fUnaryOrParen, noStmtContext, &needScanRCurly, fModule, &pFncNamePid); if (!result) { Assert(!pnodeFncBlockScope); @@ -5214,9 +5214,10 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool m_scopeCountNoAst = scopeCountNoAstSave; - if (buildAST && fDeclaration && !IsStrictMode()) + if (fDeclaration && !IsStrictMode()) { - if (pnodeFnc->sxFnc.pnodeName != nullptr && pnodeFnc->sxFnc.pnodeName->nop == knopVarDecl && + if (pFncNamePid != nullptr && + GetCurrentBlock() && GetCurrentBlock()->sxBlock.blockType == PnodeBlockType::Regular) { // Add a function-scoped VarDecl with the same name as the function for @@ -5225,9 +5226,9 @@ ParseNodePtr Parser::ParseFncDecl(ushort flags, LPCOLESTR pNameHint, const bool // level and we accomplish this by having each block scoped function // declaration assign to both the block scoped "let" binding, as well // as the function scoped "var" binding. - ParseNodePtr vardecl = CreateVarDeclNode(pnodeFnc->sxFnc.pnodeName->sxVar.pid, STVariable, false, nullptr, false); + ParseNodePtr vardecl = CreateVarDeclNode(pFncNamePid, STVariable, false, nullptr, false); vardecl->sxVar.isBlockScopeFncDeclVar = true; - if (vardecl->sxVar.sym->GetIsFormal()) + if (GetCurrentFunctionNode() && vardecl->sxVar.sym->GetIsFormal()) { GetCurrentFunctionNode()->sxFnc.SetHasAnyWriteToFormals(true); } @@ -5310,7 +5311,7 @@ void Parser::AppendFunctionToScopeList(bool fDeclaration, ParseNodePtr pnodeFnc) Parse a function definition. ***************************************************************************/ template -bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool noStmtContext, bool *pNeedScanRCurly, bool skipFormals) +bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool noStmtContext, bool *pNeedScanRCurly, bool skipFormals, IdentPtr* pFncNamePid) { ParseNodePtr pnodeFncParent = GetCurrentFunctionNode(); // is the following correct? When buildAST is false, m_currentNodeDeferredFunc can be nullptr on transition to deferred parse from non-deferred @@ -5326,6 +5327,7 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho StmtNest *pstmtSave; ParseNodePtr *lastNodeRef = nullptr; bool fFunctionInBlock = false; + if (buildAST) { fFunctionInBlock = GetCurrentBlockInfo() != GetCurrentFunctionBlockInfo() && @@ -5353,7 +5355,7 @@ bool Parser::ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, usho this->UpdateCurrentNodeFunc(pnodeFnc, fLambda); } - *pHasName = !fLambda && !fModule && this->ParseFncNames(pnodeFnc, pnodeFncSave, flags, &lastNodeRef); + *pHasName = !fLambda && !fModule && this->ParseFncNames(pnodeFnc, pnodeFncSave, flags, &lastNodeRef, pFncNamePid); if (fDeclaration) { @@ -6453,7 +6455,7 @@ void Parser::ParseNestedDeferredFunc(ParseNodePtr pnodeFnc, bool fLambda, bool * } template -bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, ushort flags, ParseNodePtr **pLastNodeRef) +bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, ushort flags, ParseNodePtr **pLastNodeRef, IdentPtr* pFncNamePid) { BOOL fDeclaration = flags & fFncDeclaration; BOOL fIsAsync = flags & fFncAsync; @@ -6543,7 +6545,6 @@ bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, u ichMinNames = m_pscan->IchMinTok(); - Assert(m_token.tk == tkID || (m_token.tk == tkYIELD && !fDeclaration)); if (IsStrictMode()) @@ -6561,6 +6562,11 @@ bool Parser::ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, u pnodeT->ichMin = ichMinBase; pnodeT->ichLim = ichLimBase; + if (pFncNamePid != nullptr) + { + *pFncNamePid = pidBase; + } + if (fDeclaration && pnodeFncParent && pnodeFncParent->sxFnc.pnodeName && diff --git a/lib/Parser/Parse.h b/lib/Parser/Parse.h index 7272096ffd3..337b0bd5b20 100644 --- a/lib/Parser/Parse.h +++ b/lib/Parser/Parse.h @@ -808,9 +808,9 @@ class Parser template void ParseComputedName(ParseNodePtr* ppnodeName, LPCOLESTR* ppNameHint, LPCOLESTR* ppFullNameHint = nullptr, uint32 *pNameLength = nullptr, uint32 *pShortNameOffset = nullptr); template ParseNodePtr ParseMemberGetSet(OpCode nop, LPCOLESTR* ppNameHint); template ParseNodePtr ParseFncDecl(ushort flags, LPCOLESTR pNameHint = NULL, const bool needsPIDOnRCurlyScan = false, bool resetParsingSuperRestrictionState = true, bool fUnaryOrParen = false); - template bool ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, ushort flags, ParseNodePtr **pLastNodeRef); + template bool ParseFncNames(ParseNodePtr pnodeFnc, ParseNodePtr pnodeFncParent, ushort flags, ParseNodePtr **pLastNodeRef, IdentPtr* pFncNamePid = nullptr); template void ParseFncFormals(ParseNodePtr pnodeFnc, ParseNodePtr pnodeParentFnc, ushort flags, bool isTopLevelDeferredFunc = false); - template bool ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool noStmtContext, bool *pNeedScanRCurly, bool skipFormals = false); + template bool ParseFncDeclHelper(ParseNodePtr pnodeFnc, LPCOLESTR pNameHint, ushort flags, bool *pHasName, bool fUnaryOrParen, bool noStmtContext, bool *pNeedScanRCurly, bool skipFormals = false, IdentPtr* pFncNamePid = nullptr); template void ParseExpressionLambdaBody(ParseNodePtr pnodeFnc); template void UpdateCurrentNodeFunc(ParseNodePtr pnodeFnc, bool fLambda); bool FncDeclAllowedWithoutContext(ushort flags); diff --git a/test/Bugs/bug_OS14115684.js b/test/Bugs/bug_OS14115684.js new file mode 100644 index 00000000000..da8aadde63c --- /dev/null +++ b/test/Bugs/bug_OS14115684.js @@ -0,0 +1,17 @@ +//------------------------------------------------------------------------------------------------------- +// Copyright (C) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information. +//------------------------------------------------------------------------------------------------------- + +function test(foo) { + function nest() { + { + function foo() { + console.log('pass'); + } + } + foo(); + } + nest(); +} +test(()=>console.log('fail')); diff --git a/test/Bugs/rlexe.xml b/test/Bugs/rlexe.xml index 13af99481aa..ce228bac251 100644 --- a/test/Bugs/rlexe.xml +++ b/test/Bugs/rlexe.xml @@ -444,4 +444,11 @@ -args summary -endargs + + + bug_OS14115684.js + BugFix + -forceundodefer + +