Skip to content

Commit e35eca1

Browse files
committed
[MERGE chakra-core#3645 @pleath] [MSFT 12313182] Detect assignment to const in nested functions that were originally deferred.
Merge pull request chakra-core#3645 from pleath:12313128 Add symbol-is-const flag to Symbol and to ScopeInfo to allow us to detect this case. Don't rely on having access to a parse node for the declaration.
2 parents 9ae3e2a + 8f40df4 commit e35eca1

8 files changed

Lines changed: 45 additions & 6 deletions

File tree

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5169,7 +5169,7 @@ void ByteCodeGenerator::EmitPropStore(Js::RegSlot rhsLocation, Symbol *sym, Iden
51695169
}
51705170
else if (sym->IsInSlot(funcInfo) || envIndex != -1)
51715171
{
5172-
if (!isConstDecl && sym->GetDecl() && sym->GetDecl()->nop == knopConstDecl)
5172+
if (!isConstDecl && sym->GetIsConst())
51735173
{
51745174
// This is a case where const reassignment can't be proven statically (e.g., eval, with) so
51755175
// we have to catch it at runtime.

lib/Runtime/ByteCode/ByteCodeGenerator.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,6 +3552,7 @@ void PreVisitBlock(ParseNode *pnodeBlock, ByteCodeGenerator *byteCodeGenerator)
35523552
#endif
35533553
sym->SetIsGlobal(isGlobalScope);
35543554
sym->SetIsBlockVar(true);
3555+
sym->SetIsConst(pnode->nop == knopConstDecl);
35553556
sym->SetNeedDeclaration(true);
35563557
pnode->sxVar.sym = sym;
35573558
};

lib/Runtime/ByteCode/ScopeInfo.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ namespace Js
3333
this->SetSymbolType(scopeSlot, sym->GetSymbolType());
3434
this->SetHasFuncAssignment(scopeSlot, sym->GetHasFuncAssignment());
3535
this->SetIsBlockVariable(scopeSlot, sym->GetIsBlockVar());
36+
this->SetIsConst(scopeSlot, sym->GetIsConst());
3637
this->SetIsFuncExpr(scopeSlot, sym->GetIsFuncExpr());
3738
this->SetIsModuleExportStorage(scopeSlot, sym->GetIsModuleExportStorage());
3839
this->SetIsModuleImport(scopeSlot, sym->GetIsModuleImport());
@@ -235,6 +236,7 @@ namespace Js
235236

236237
sym->SetScopeSlot(static_cast<PropertyId>(i));
237238
sym->SetIsBlockVar(GetIsBlockVariable(i));
239+
sym->SetIsConst(GetIsConst(i));
238240
sym->SetIsFuncExpr(GetIsFuncExpr(i));
239241
sym->SetIsModuleExportStorage(GetIsModuleExportStorage(i));
240242
sym->SetIsModuleImport(GetIsModuleImport(i));

lib/Runtime/ByteCode/ScopeInfo.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,12 @@ namespace Js {
2727
Field(PropertyRecord const*) name;
2828
};
2929
Field(SymbolType) symbolType;
30-
Field(bool) hasFuncAssignment;
31-
Field(bool) isBlockVariable;
32-
Field(bool) isFuncExpr;
33-
Field(bool) isModuleExportStorage;
34-
Field(bool) isModuleImport;
30+
Field(bool) hasFuncAssignment : 1;
31+
Field(bool) isBlockVariable : 1;
32+
Field(bool) isConst : 1;
33+
Field(bool) isFuncExpr : 1;
34+
Field(bool) isModuleExportStorage : 1;
35+
Field(bool) isModuleImport : 1;
3536
};
3637

3738
private:
@@ -86,6 +87,13 @@ namespace Js {
8687
symbols[i].isBlockVariable = is;
8788
}
8889

90+
void SetIsConst(int i, bool is)
91+
{
92+
Assert(!areNamesCached);
93+
Assert(i >= 0 && i < symbolCount);
94+
symbols[i].isConst = is;
95+
}
96+
8997
void SetIsFuncExpr(int i, bool is)
9098
{
9199
Assert(!areNamesCached);
@@ -151,6 +159,12 @@ namespace Js {
151159
return symbols[i].isBlockVariable;
152160
}
153161

162+
bool GetIsConst(int i)
163+
{
164+
Assert(i >= 0 && i < symbolCount);
165+
return symbols[i].isConst;
166+
}
167+
154168
bool GetIsFuncExpr(int i)
155169
{
156170
Assert(i >= 0 && i < symbolCount);

lib/Runtime/ByteCode/Symbol.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Symbol
3030
BYTE defCount;
3131
BYTE needDeclaration : 1;
3232
BYTE isBlockVar : 1;
33+
BYTE isConst : 1;
3334
BYTE isGlobal : 1;
3435
BYTE isEval : 1;
3536
BYTE hasNonLocalReference : 1; // if true, then this symbol needs to be heap-allocated
@@ -61,6 +62,7 @@ class Symbol
6162
location(Js::Constants::NoRegister),
6263
needDeclaration(false),
6364
isBlockVar(false),
65+
isConst(false),
6466
isGlobal(false),
6567
hasNonLocalReference(false),
6668
isFuncExpr(false),
@@ -150,6 +152,16 @@ class Symbol
150152
return isBlockVar;
151153
}
152154

155+
void SetIsConst(bool is)
156+
{
157+
isConst = is;
158+
}
159+
160+
bool GetIsConst() const
161+
{
162+
return isConst;
163+
}
164+
153165
void SetIsModuleExportStorage(bool is)
154166
{
155167
isModuleExportStorage = is;

test/LetConst/AssignmentToConst.baseline

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,5 @@ test 23
4646
ReferenceError: Use before declaration
4747
test 24
4848
ReferenceError: Use before declaration
49+
test 25
50+
TypeError: Assignment to const

test/LetConst/AssignmentToConst.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@ try { eval("WScript.Echo('test 21'); const x = 1; {const x = 2; x++;}"); WScript
2727
try { eval("WScript.Echo('test 22'); const x = 1; {const x = 2;} x++;"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); }
2828
try { eval("WScript.Echo('test 23'); x = 1; {let x = 2;} const x = 10;"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); }
2929
try { eval("WScript.Echo('test 24'); function f() {x = 1; {let x = 2;} const x = 10;} f();"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); }
30+
try { eval("WScript.Echo('test 25'); const x = 10; function f() {x = 1; {let x = 2;} } f();"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); }
3031

3132

test/LetConst/rlexe.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,13 @@
141141
<baseline>AssignmentToConst.baseline</baseline>
142142
</default>
143143
</test>
144+
<test>
145+
<default>
146+
<files>AssignmentToConst.js</files>
147+
<baseline>AssignmentToConst.baseline</baseline>
148+
<compile-flags>-force:deferparse</compile-flags>
149+
</default>
150+
</test>
144151
<test>
145152
<default>
146153
<files>DeclOutofBlock.js</files>

0 commit comments

Comments
 (0)