From 19051e7d799fa59aa6a5704c1121d9af2f00a7f7 Mon Sep 17 00:00:00 2001 From: lye Date: Thu, 20 Dec 2018 18:42:12 -0800 Subject: [PATCH] Hoisting fixes (#2606) When hoisting a var, use UNKNOWN_EXPRESSION as the initializer instead of the actual one. This prevents the initializer from being used during the optimization step when it hasn't yet been assigned at runtime. --- src/ast/scopes/BlockScope.ts | 8 +++++++- .../hoisted-variable-case-stmt/_config.js | 3 +++ .../hoisted-variable-case-stmt/_expected.js | 8 ++++++++ .../samples/hoisted-variable-case-stmt/main.js | 8 ++++++++ .../hoisted-variable-if-stmt/._expected.js.swp | Bin 0 -> 12288 bytes .../hoisted-variable-if-stmt/.main.js.swp | Bin 0 -> 12288 bytes .../samples/hoisted-variable-if-stmt/_config.js | 4 ++++ .../hoisted-variable-if-stmt/_expected.js | 15 +++++++++++++++ .../samples/hoisted-variable-if-stmt/main.js | 15 +++++++++++++++ 9 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/form/samples/hoisted-variable-case-stmt/_config.js create mode 100644 test/form/samples/hoisted-variable-case-stmt/_expected.js create mode 100644 test/form/samples/hoisted-variable-case-stmt/main.js create mode 100644 test/form/samples/hoisted-variable-if-stmt/._expected.js.swp create mode 100644 test/form/samples/hoisted-variable-if-stmt/.main.js.swp create mode 100644 test/form/samples/hoisted-variable-if-stmt/_config.js create mode 100644 test/form/samples/hoisted-variable-if-stmt/_expected.js create mode 100644 test/form/samples/hoisted-variable-if-stmt/main.js diff --git a/src/ast/scopes/BlockScope.ts b/src/ast/scopes/BlockScope.ts index 838e6a2b7d8..fca384856c0 100644 --- a/src/ast/scopes/BlockScope.ts +++ b/src/ast/scopes/BlockScope.ts @@ -1,6 +1,7 @@ import { AstContext } from '../../Module'; import Identifier from '../nodes/Identifier'; import { ExpressionEntity } from '../nodes/shared/Expression'; +import { UNKNOWN_EXPRESSION } from '../values'; import LocalVariable from '../variables/LocalVariable'; import Scope from './Scope'; @@ -14,7 +15,12 @@ export default class BlockScope extends Scope { isHoisted: boolean = false ) { if (isHoisted) { - return this.parent.addDeclaration(identifier, context, init, true) as LocalVariable; + return this.parent.addDeclaration( + identifier, + context, + UNKNOWN_EXPRESSION, + true + ) as LocalVariable; } else { return super.addDeclaration(identifier, context, init, false) as LocalVariable; } diff --git a/test/form/samples/hoisted-variable-case-stmt/_config.js b/test/form/samples/hoisted-variable-case-stmt/_config.js new file mode 100644 index 00000000000..f4ec792209e --- /dev/null +++ b/test/form/samples/hoisted-variable-case-stmt/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'Properly handles a variable hoisted from within a fallthrough switch case' +}; diff --git a/test/form/samples/hoisted-variable-case-stmt/_expected.js b/test/form/samples/hoisted-variable-case-stmt/_expected.js new file mode 100644 index 00000000000..872b496dacf --- /dev/null +++ b/test/form/samples/hoisted-variable-case-stmt/_expected.js @@ -0,0 +1,8 @@ +switch (someGlobal) { + case 1: + var hoisted = true; + case 2: + if (hoisted) { + throw "failed"; + } +} diff --git a/test/form/samples/hoisted-variable-case-stmt/main.js b/test/form/samples/hoisted-variable-case-stmt/main.js new file mode 100644 index 00000000000..872b496dacf --- /dev/null +++ b/test/form/samples/hoisted-variable-case-stmt/main.js @@ -0,0 +1,8 @@ +switch (someGlobal) { + case 1: + var hoisted = true; + case 2: + if (hoisted) { + throw "failed"; + } +} diff --git a/test/form/samples/hoisted-variable-if-stmt/._expected.js.swp b/test/form/samples/hoisted-variable-if-stmt/._expected.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..d085cba3a72421881939f95ccedd6a9a4f4f5361 GIT binary patch literal 12288 zcmeI&Jxjwt7zgmD?xN`GaK^zFY_8QsD1HD3N1cR{HkUSf?Zw>H7etHnOSmf{_zgsH zb98oB`~rRfpU@Yu6gn&agFlztb9W)X?MP~+z3m;b>6eMyJkeWqY5(ZqmG0Mw^qI;= zr#5#I>$uT$(hO%x#B~znyCy`EBCnJ-#qzzh$R#rAmY@G^=$3YqgHLZ$qRJ5+; zWL2Fes?H_JWgyB!OAlSTC2d%8Iuv78iCWO~M!iAOHafKmY;|fB*y_@J|I? zlA|ua+sxqo<_3LktRLK>g8&2|009U<00Izz00bZa0SG|g4+;b!(JCMMyV=2?zyA-< z|KEJ^#rfoXaNapDoM+Ax=aF;Ax#iq&t~pnnY@Z$n4FV8=00bZa0SG_<0uX=z1Rwx` zk-!BBZgtbPMk`;NM&2`rUZFy9B=WT&Er@fX{v`e-Uhs(65-#ni3XKZCR<})}hU+6^ P#@6#lf9ojFR%OK>v3^_P literal 0 HcmV?d00001 diff --git a/test/form/samples/hoisted-variable-if-stmt/.main.js.swp b/test/form/samples/hoisted-variable-if-stmt/.main.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..4ed19362e5771d02e39fde7d54cae0ad8ca731f7 GIT binary patch literal 12288 zcmeI&u}Z^07zgmL?xH9-Ih=86!S-5R1n~hJ9CcD8Z7=QVB^Pp6MMNFlExv=|toQ`( zIx9YeFW?v3LRCs<^?&f^lDm&Dz0Ry(hn<-;)3Vcn>*j>^u*UdEwL zD*JBSBd`wv2#ge%q?P4bHQ!zg7R2n#*2qe1KmY;|fB*y_009U<00Mtcz^4T|=hvF( zzuHuPE_|E&x0oOR0SG_<0uX=z1Rwwb2tWV=5cq`xVUuW%5B*7g@aOOUgY*A8U%YW% zIWL?i&I9M3bH};iTyeUbOU?x+<>Y;KIT#Rt00bZa0SG_<0uX=z1Rwx`e QS>B0PzI2L0<33w`01Q-PsQ>@~ literal 0 HcmV?d00001 diff --git a/test/form/samples/hoisted-variable-if-stmt/_config.js b/test/form/samples/hoisted-variable-if-stmt/_config.js new file mode 100644 index 00000000000..c6e376a856b --- /dev/null +++ b/test/form/samples/hoisted-variable-if-stmt/_config.js @@ -0,0 +1,4 @@ +module.exports = { + description: + 'Properly renders branches which refer to hoisted variables from other lexical scopes' +}; diff --git a/test/form/samples/hoisted-variable-if-stmt/_expected.js b/test/form/samples/hoisted-variable-if-stmt/_expected.js new file mode 100644 index 00000000000..a7ac1cf18f7 --- /dev/null +++ b/test/form/samples/hoisted-variable-if-stmt/_expected.js @@ -0,0 +1,15 @@ +if (false) { + var foo; +} + +if (foo) { + console.log("nope"); +} + +{ + var bar = true; +} + +if (bar) { + console.log("ok"); +} diff --git a/test/form/samples/hoisted-variable-if-stmt/main.js b/test/form/samples/hoisted-variable-if-stmt/main.js new file mode 100644 index 00000000000..8f57f22a1cc --- /dev/null +++ b/test/form/samples/hoisted-variable-if-stmt/main.js @@ -0,0 +1,15 @@ +if (false) { + var foo = true; +} + +if (foo) { + console.log("nope"); +} + +if (true) { + var bar = true; +} + +if (bar) { + console.log("ok"); +}