Skip to content

Commit 9fa551a

Browse files
committed
fix(semantic): handle edge cases checking super (#13499)
Fixes #13284. Fix semantic's checking of `super()` and `super.prop`. This fixes various TS test cases, notably correctly identifying that these are all illegal: ```js class C { prop = function() { super.foo }; [super.foo]() {} @super.foo method() {} }; ``` It also fixes various edge cases related to classes nested within other classes that aren't covered by existing conformance tests. It's pretty much a complete re-write. I've combined the 2 paths for in a class and not in a class into one, to avoid repeated code. This PR includes pass + fail test fixtures which include `super` in every conceivable position I could think of. There are so many errors in the fail test fixtures, that I had to write a script to check the snapshot includes them all! Hopefully this solves this issue for once and for all! Note: The large pass fixture seems to be revealing bugs somewhere in transformer - there's a mismatch, as well as lots of wrong scopes. But that's incidental to this PR, and can be addressed separately.
1 parent bf50a02 commit 9fa551a

File tree

10 files changed

+3954
-102
lines changed

10 files changed

+3954
-102
lines changed

crates/oxc_semantic/src/checker/javascript.rs

Lines changed: 236 additions & 77 deletions
Large diffs are not rendered by default.
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
// `super()` not in a class or object method
2+
super();
3+
() => () => 123 + super();
4+
if (true) { while (false) { { super(); } } }
5+
() => (arg = super()) => {
6+
super();
7+
() => () => 123 + super();
8+
if (true) { while (false) { { super(); } } }
9+
};
10+
11+
// `super()` in a function
12+
function f(arg = super()) {
13+
super();
14+
() => () => 123 + super();
15+
if (true) { while (false) { { super(); } } }
16+
}
17+
f = function(arg = super()) {
18+
super();
19+
() => () => 123 + super();
20+
if (true) { while (false) { { super(); } } }
21+
};
22+
23+
// `super()` in class constructor of class without super class
24+
class A {
25+
constructor(arg = super()) {
26+
super();
27+
() => (arg = super()) => 123 + super();
28+
if (true) { while (false) { { super(); } } }
29+
}
30+
}
31+
32+
// `super()` in class properties
33+
class B extends Super {
34+
prop = super();
35+
static prop = () => (arg = super()) => 123 + super();
36+
37+
accessor access = super();
38+
static accessor access = () => () => 123 + super();
39+
}
40+
41+
// `super()` in class methods / getters / setters
42+
class C extends Super {
43+
method(arg = super()) {
44+
super();
45+
() => (arg = super()) => 123 + super();
46+
if (true) { while (false) { { super(); } } }
47+
}
48+
49+
static method(arg = super()) {
50+
super();
51+
() => (arg = super()) => 123 + super();
52+
if (true) { while (false) { { super(); } } }
53+
}
54+
55+
['x'](arg = super()) {
56+
super();
57+
() => (arg = super()) => 123 + super();
58+
if (true) { while (false) { { super(); } } }
59+
}
60+
61+
static ['x'](arg = super()) {
62+
super();
63+
() => (arg = super()) => 123 + super();
64+
if (true) { while (false) { { super(); } } }
65+
}
66+
67+
get y() {
68+
super();
69+
() => (arg = super()) => 123 + super();
70+
if (true) { while (false) { { super(); } } }
71+
}
72+
73+
set y(arg = super()) {
74+
super();
75+
() => (arg = super()) => 123 + super();
76+
if (true) { while (false) { { super(); } } }
77+
}
78+
79+
static get y() {
80+
super();
81+
() => (arg = super()) => 123 + super();
82+
if (true) { while (false) { { super(); } } }
83+
}
84+
85+
static set y(arg = super()) {
86+
super();
87+
() => (arg = super()) => 123 + super();
88+
if (true) { while (false) { { super(); } } }
89+
}
90+
}
91+
92+
// `super()` in class static block
93+
class D extends Super {
94+
static {
95+
super();
96+
() => (arg = super()) => 123 + super();
97+
if (true) { while (false) { { super(); } } }
98+
}
99+
}
100+
101+
// `super()` in function or object method inside class constructor
102+
class E extends Super {
103+
constructor() {
104+
function inner(arg = super()) {
105+
super();
106+
() => (arg = super()) => 123 + super();
107+
if (true) { while (false) { { super(); } } }
108+
}
109+
f = () => function(arg = super()) {
110+
super();
111+
() => (arg = super()) => 123 + super();
112+
if (true) { while (false) { { super(); } } }
113+
};
114+
obj = {
115+
method(arg = super()) {
116+
super();
117+
() => (arg = super()) => 123 + super();
118+
if (true) { while (false) { { super(); } } }
119+
},
120+
set x(arg = super()) {
121+
super();
122+
() => (arg = super()) => 123 + super();
123+
if (true) { while (false) { { super(); } } }
124+
},
125+
};
126+
}
127+
}
128+
129+
// `super()` in class computed keys
130+
class F extends Super {
131+
[super()] = 1;
132+
static [(arg = super()) => super()] = 2;
133+
accessor [123 + super()] = 3;
134+
static accessor [() => (arg = super()) => 123 + super()] = 4;
135+
[super()]() {};
136+
static [() => super()]() {};
137+
get [super()]() {};
138+
static get [() => super()]() {};
139+
set [super()](v) {};
140+
static set [() => () => 123 + super()](v) {};
141+
}
142+
143+
// `super()` in class extends
144+
class G extends super() {}
145+
class H extends (() => () => 123 + super()) {}
146+
147+
// `super()` in class decorators
148+
@super()
149+
class I extends Super {
150+
@super() prop = 1;
151+
@super() static prop = 2;
152+
@super() accessor access = 3;
153+
@super() static accessor access = 4;
154+
@super() method() {}
155+
}
156+
157+
// `super()` in properties / methods of class inside class constructor
158+
class J extends Super {
159+
constructor() {
160+
class Inner {
161+
prop = super();
162+
static prop = (arg = super()) => 123 + super();
163+
accessor access = super();
164+
static accessor access = (arg = super()) => 123 + super();
165+
method() { super(); }
166+
static method() { (arg = super()) => 123 + super(); }
167+
get x() { super(); }
168+
static get y() { (arg = super()) => 123 + super(); }
169+
set x(v) { super(); }
170+
static set y(v) { (arg = super()) => 123 + super(); }
171+
static { super(); }
172+
}
173+
}
174+
}
175+
176+
// `super()` in computed keys of class inside class property
177+
class K extends Super {
178+
prop = class Inner {
179+
[super()] = 1;
180+
static [(arg = super()) => super()] = 2;
181+
accessor [123 + super()] = 3;
182+
static accessor [() => (arg = super()) => 123 + super()] = 4;
183+
[super()]() {};
184+
static [() => super()]() {};
185+
get [super()]() {};
186+
static get [() => super()]() {};
187+
set [super()](v) {};
188+
static set [() => () => 123 + super()](v) {};
189+
};
190+
}
191+
192+
// `super()` in computed keys of class inside class method
193+
class L extends Super {
194+
method() {
195+
class Inner {
196+
[super()] = 1;
197+
static [(arg = super()) => super()] = 2;
198+
accessor [123 + super()] = 3;
199+
static accessor [() => (arg = super()) => 123 + super()] = 4;
200+
[super()]() {};
201+
static [() => super()]() {};
202+
get [super()]() {};
203+
static get [() => super()]() {};
204+
set [super()](v) {};
205+
static set [() => () => 123 + super()](v) {};
206+
}
207+
}
208+
}
209+
210+
// `super()` in extends clause of class inside class property
211+
class M extends Super {
212+
prop1 = class Inner extends super() {};
213+
prop2 = class Inner extends (() => (arg = super()) => 123 + super()) {};
214+
}
215+
216+
// `super()` in extends clause of class inside class method
217+
class N extends Super {
218+
method() {
219+
class Inner1 extends super() {};
220+
class Inner2 extends (() => (arg = super()) => 123 + super()) {};
221+
}
222+
}
223+
224+
// `super()` in decorators of class inside class property
225+
class O extends Super {
226+
prop = @super() class Inner extends Super {
227+
@super() prop = 1;
228+
@super() static prop = 2;
229+
@super() accessor access = 3;
230+
@super() static accessor access = 4;
231+
@super() method() {}
232+
};
233+
}
234+
235+
// `super()` in decorators of class inside class method
236+
class P extends Super {
237+
method() {
238+
@super()
239+
class Inner extends Super {
240+
@super() prop = 1;
241+
@super() static prop = 2;
242+
@super() accessor access = 3;
243+
@super() static accessor access = 4;
244+
@super() method() {}
245+
}
246+
}
247+
}
248+
249+
// `super()` in deeply nested classes inside class method
250+
class Q extends Super {
251+
method() {
252+
class A {
253+
[
254+
class B {
255+
[
256+
class C {
257+
[super()]() {}
258+
}
259+
]() {}
260+
}
261+
]() {}
262+
}
263+
264+
class D extends class E extends class F extends super() {} {} {}
265+
266+
class G {
267+
@(
268+
class H {
269+
@(
270+
class I {
271+
@super()
272+
method() {}
273+
}
274+
)
275+
method() {}
276+
}
277+
)
278+
method() {}
279+
}
280+
}
281+
}
282+
283+
// `super()` in object methods
284+
obj = {
285+
method() {
286+
super();
287+
() => (arg = super()) => 123 + super();
288+
if (true) { while (false) { { super(); } } }
289+
},
290+
['x']() {
291+
super();
292+
() => (arg = super()) => 123 + super();
293+
if (true) { while (false) { { super(); } } }
294+
},
295+
get x() {
296+
super();
297+
() => (arg = super()) => 123 + super();
298+
if (true) { while (false) { { super(); } } }
299+
},
300+
set x(v) {
301+
super();
302+
() => (arg = super()) => 123 + super();
303+
if (true) { while (false) { { super(); } } }
304+
},
305+
};

0 commit comments

Comments
 (0)