Skip to content

Commit 8b32043

Browse files
rishipalcopybara-github
authored andcommitted
Compute variable liveness for optional chaining
PiperOrigin-RevId: 321821942
1 parent f224671 commit 8b32043

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

src/com/google/javascript/jscomp/LiveVariablesAnalysis.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,22 @@ private void computeGenKill(Node n, BitSet gen, BitSet kill, boolean conditional
298298
case AND:
299299
case OR:
300300
case COALESCE:
301+
case OPTCHAIN_GETELEM:
302+
case OPTCHAIN_GETPROP:
301303
computeGenKill(n.getFirstChild(), gen, kill, conditional);
302304
// May short circuit.
303305
computeGenKill(n.getLastChild(), gen, kill, true);
304306
return;
305307

308+
case OPTCHAIN_CALL:
309+
computeGenKill(n.getFirstChild(), gen, kill, conditional);
310+
// Unlike OPTCHAIN_GETPROP and OPTCHAIN_GETELEM, the OPTCHAIN_CALLs can have multiple
311+
// children on rhs which get executed conditionally
312+
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
313+
computeGenKill(c, gen, kill, true);
314+
}
315+
return;
316+
306317
case HOOK:
307318
computeGenKill(n.getFirstChild(), gen, kill, conditional);
308319
// Assume both sides are conditional.

test/com/google/javascript/jscomp/LiveVariablesAnalysisTest.java

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,57 @@ public void nullishCoalesce() {
109109
assertLiveBeforeX("var a,b;X:if(b??a) {}", "a");
110110
assertLiveBeforeX("var a,b;X:if(b??b(a)) {}", "a");
111111

112-
// The kill can be "conditional" due to short circuit.
112+
// Unconditionally killed on lhs of ??
113113
assertNotLiveAfterX("var a,b;X:a();if((a=b)??b){}a()", "a");
114114
assertNotLiveAfterX("var a,b;X:a();while((a=b)??b){}a()", "a");
115-
assertLiveBeforeX("var a,b;a();X:if(b??(a=b)){}a()", "a"); // Assumed live.
116-
assertLiveBeforeX("var a,b;a();X:if(a??(a=b)){}a()", "a");
117-
assertLiveBeforeX("var a,b;a();X:while(b??(a=b)){}a()", "a");
118-
assertLiveBeforeX("var a,b;a();X:while(a??(a=b)){}a()", "a");
115+
116+
// The kill can be "conditional" due to short circuit.
117+
assertLiveBeforeX("var a,b; X:if(b??(a=b)){}a()", "a"); // Assumed live.
118+
assertLiveBeforeX("var a,b; X:if(a??(a=b)){}a()", "a");
119+
assertLiveBeforeX("var a,b; X:while(b??(a=b)){}a()", "a");
120+
assertLiveBeforeX("var a,b; X:while(a??(a=b)){}a()", "a");
121+
}
122+
123+
@Test
124+
public void optionalChainingGetProp() {
125+
// Reading the var on lhs of opt chain makes the variable live.
126+
assertNotLiveBeforeX("var a,b; X:if(b) {}", "a");
127+
assertLiveBeforeX("var a,b; X:if(a?.b) {}", "a");
128+
129+
// Reading a prop with the same name as var does not make the var live
130+
assertNotLiveBeforeX("var a,b;X:if(b?.a) {}", "a");
131+
132+
// unconditional kill on lhs of ?.
133+
assertNotLiveAfterX("var a,b;X:a();if((a=c)?.b){} a()", "a");
134+
assertNotLiveAfterX("var a,b;X:a();while((a=b)?.b){} a()", "a");
135+
}
136+
137+
@Test
138+
public void optionalChainingCall() {
139+
// conditionally accessing var keeps it live
140+
assertLiveBeforeX("var a,b; X:if(b?.(a)){}", "a");
141+
// conditionally overwriting var does not kill it
142+
assertLiveBeforeX("var a,b; X:if(b?.(a=c)){} a();", "a");
143+
144+
// conditional overwrite on rhs of ?. does not kill the var
145+
assertLiveBeforeX("var a,b; X:if(b?.(a=b)){}a()", "a"); // Assumed live.
146+
assertLiveBeforeX("var a,b; X:if(a?.(a=b)){}a()", "a");
147+
assertLiveBeforeX("var a,b; X:while(b?.(a=b)){}a()", "a");
148+
assertLiveBeforeX("var a,b; X:while(a?.(a=b)){}a()", "a");
149+
}
150+
151+
@Test
152+
public void optionalChainingGetElem() {
153+
// conditionally accessing var keeps it live
154+
assertLiveBeforeX("var a,b; X:if(b?.[a]) {}", "a");
155+
// conditionally overwriting var does not kill it
156+
assertLiveBeforeX("var a,b; X:if(b?.[a=c]) {} a();", "a");
157+
158+
// conditional overwrite on rhs of ?. does not kill the var
159+
assertLiveBeforeX("var a,b; X:if(b?.[a=b]){}a()", "a"); // Assumed live.
160+
assertLiveBeforeX("var a,b; X:if(a?.[a=b]){}a()", "a");
161+
assertLiveBeforeX("var a,b; X:while(b?.[a=b]){}a()", "a");
162+
assertLiveBeforeX("var a,b; X:while(a?.[a=b]){}a()", "a");
119163
}
120164

121165
@Test

0 commit comments

Comments
 (0)