Files
test-repo/tests/super/constructor.js
T
Christopher Chedeau cf45afba61 Add testing
- This brings in the flow test suite that contains a ton of JavaScript parsing edge cases
- This creates snapshot tests using the pretty printer for all of them
- If uncomment `RUN_AST_TESTS` line in `tests/run_specs.js`, it checks ast(pretty_print(x)) == ast(x). Right now, "178 failed, 197 passed, 375 of 377 total". So half of the tests are not passing, most of them are crashes and many of the rest are subtle issues.
2016-12-23 19:51:53 +00:00

155 lines
2.9 KiB
JavaScript

class A { x: number; }
class B {
x: number;
constructor() {
this.x; // OK
}
}
class C extends A { }
class D extends A {
y: number;
constructor() {
this.y; // error (no super call)
this.x; // error (no super call)
}
}
class E extends A {
y: number;
constructor() {
super();
this.y; // OK
this.x; // OK
}
}
function leak(f) {
f.y; // error
f.x; // error
}
class F extends A {
y: number;
constructor() {
leak(this); // error (no super call yet)
super();
this.y;
this.x;
}
}
class G extends A {
constructor(b) {
super.x; // error (no super call)
}
}
class H extends A {
y: number;
constructor() {
if (Math.random() < 0.5)
super();
else
super();
this.y; // OK
this.x; // OK
}
}
class I_ {
constructor(leaked_this) {
leaked_this.foo()
}
foo() { }
}
class I extends I_ {
constructor() {
super(this); // error (no super call yet)
}
}
class J__ { }
class J_ extends J__ {
constructor(closure_leaking_this) {
closure_leaking_this();
super();
}
foo() { }
}
class J extends J_ {
constructor() {
super(() => this.foo()); // error (no super call yet)
// The reason for this error is that super constructor could call the
// closure and therefore access this before calling its own super
// constructor (as shown above). The only safe thing to do in the super
// constructor is to save the closure so that it can be called later, after
// initialization is done (as shown below).
}
}
class K_ {
closure_leaking_this: () => void;
constructor(closure_leaking_this) {
this.closure_leaking_this = closure_leaking_this;
}
foo() { }
}
class K extends K_ {
constructor() {
super(() => { if (_this) _this.foo() }); // OK
var _this = this;
this.closure_leaking_this();
}
}
// even though super() calls the parent's constructor(), it does not do the same
// conversion on non-objects. so `new L_()` returns an instance of `L_` because
// the constructor returns false (a non-object), but `super()` returns false,
// which then similarly causes `new L()` to return an instance of `L`.
class L_ {
constructor() {
return false;
}
}
class L extends L_ {
constructor() {
let x: boolean = super();
return x;
}
}
(new L_(): L_);
(new L(): L);
// similarly, the converse is true: if the parent's constructor returns an
// object, then the child does too.
class M_ {
constructor() {
return {foo: 'foo'};
}
}
class M extends M_ {
constructor() {
return super();
}
}
(new M_(): {foo: string});
(new M(): {foo: string});
// however! super() calls the parent constructor with the subclass as its `this`
// value (essentially `super.constructor.call(this)`).
class N_ {
constructor(): this {
let x = this;
return x;
}
}
class N extends N_ {
constructor() {
return super();
}
}
(new N_(): N_);
(new N(): N);