552 lines
12 KiB
Plaintext
552 lines
12 KiB
Plaintext
exports[`test class_expr.js 1`] = `
|
|
"/* @flow */
|
|
// issue #1191
|
|
|
|
const Thing = class Thing {
|
|
zark() {
|
|
this.x = 123; // error: property not found (must be declared)
|
|
}
|
|
};
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
/* @flow */
|
|
// issue #1191
|
|
|
|
const Thing = class Thing {
|
|
zark() {
|
|
this.x = 123; // error: property not found (must be declared)
|
|
}
|
|
};"
|
|
`;
|
|
|
|
exports[`test contra.js 1`] = `
|
|
"// Counterexample with contravariant this type
|
|
|
|
class C {
|
|
next: this; // error (see below for exploit): \`this\` should only appear in
|
|
// covariant positions
|
|
}
|
|
|
|
class D extends C { }
|
|
|
|
var d = new D();
|
|
(d: C).next = new C;
|
|
(d.next: D); // sneaky
|
|
|
|
class A {
|
|
foo<X: this>(that: X) { } // error: can\'t hide contravariance using a bound
|
|
}
|
|
|
|
class B extends A {
|
|
foo<Y: this>(that: Y) { } // error (see above, catches hidden override)
|
|
}
|
|
|
|
// covariance checks on this type in invariant positions
|
|
|
|
class Invariant {
|
|
out_object(): { _: this } { return { _: this }; }
|
|
in_object(_: { _: this }) { }
|
|
inout_object: { _: this };
|
|
|
|
out_array(): Array<this> { return [this]; }
|
|
in_array(_: Array<this>) { }
|
|
inout_array: Array<this>;
|
|
}
|
|
|
|
// covariance checks on this type as type args
|
|
|
|
class Misc {
|
|
// Set<X> has invariant X
|
|
out_set(): Set<this> { return new Set().add(this); }
|
|
in_set(_: Set<this>) { }
|
|
inout_set: Set<this>;
|
|
|
|
// Promise<X> has covariant X
|
|
async out_promise(): Promise<this> { return this; }
|
|
in_promise(_: Promise<this>) { }
|
|
inout_promise: Promise<this>;
|
|
|
|
// Generator<X,Y,Z> has covariant X, covariant Y, contravariant Z
|
|
*out_generator(): Generator<this,this,this> {
|
|
yield this;
|
|
return this;
|
|
}
|
|
in_generator(_: Generator<this,this,this>) { }
|
|
inout_generator: Generator<this,this,this>;
|
|
}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Counterexample with contravariant this type
|
|
|
|
class C {
|
|
next: this; // error (see below for exploit): \`this\` should only appear in
|
|
// covariant positions
|
|
}
|
|
|
|
class D extends C {}
|
|
|
|
var d = new D;
|
|
(d: C).next = new C;
|
|
(d.next: D);
|
|
// sneaky
|
|
class A {
|
|
foo<X: this>(that: X) {} // error: can\'t hide contravariance using a bound
|
|
}
|
|
|
|
class B extends A {
|
|
foo<Y: this>(that: Y) {} // error (see above, catches hidden override)
|
|
}
|
|
|
|
// covariance checks on this type in invariant positions
|
|
class Invariant {
|
|
out_object(): { _: this } {
|
|
return { _: this };
|
|
}
|
|
in_object(_: { _: this }) {}
|
|
inout_object: { _: this };
|
|
|
|
out_array(): Array<this> {
|
|
return [ this ];
|
|
}
|
|
in_array(_: Array<this>) {}
|
|
inout_array: Array<this>;
|
|
}
|
|
|
|
// covariance checks on this type as type args
|
|
class Misc {
|
|
// Set<X> has invariant X
|
|
out_set(): Set<this> {
|
|
return new Set.add(this);
|
|
}
|
|
in_set(_: Set<this>) {}
|
|
inout_set: Set<this>;
|
|
|
|
// Promise<X> has covariant X
|
|
async out_promise(): Promise<this> {
|
|
return this;
|
|
}
|
|
in_promise(_: Promise<this>) {}
|
|
inout_promise: Promise<this>;
|
|
|
|
// Generator<X,Y,Z> has covariant X, covariant Y, contravariant Z
|
|
*out_generator(): Generator<this, this, this> {
|
|
yield this;
|
|
return this;
|
|
}
|
|
in_generator(_: Generator<this, this, this>) {}
|
|
inout_generator: Generator<this, this, this>;
|
|
}"
|
|
`;
|
|
|
|
exports[`test export.js 1`] = `
|
|
"export class A1 {
|
|
foo(): this { return this; }
|
|
bar(): this { return this; }
|
|
}
|
|
|
|
export class A2<X> {
|
|
foo(): this { return this; }
|
|
bar(): this { return this; }
|
|
qux(x: X): X { return x; }
|
|
}
|
|
|
|
export class A3<X> extends A2<X> {}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
export class A1 {
|
|
foo(): this {
|
|
return this;
|
|
}
|
|
bar(): this {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
export class A2<X> {
|
|
foo(): this {
|
|
return this;
|
|
}
|
|
bar(): this {
|
|
return this;
|
|
}
|
|
qux(x: X): X {
|
|
return x;
|
|
}
|
|
}
|
|
|
|
export class A3<X> extends A2<X> {}"
|
|
`;
|
|
|
|
exports[`test generics.js 1`] = `
|
|
"class Generic<X> {
|
|
clone(): Generic<X> { return this; }
|
|
}
|
|
|
|
class Implicit<X> { arg: X; val: X; }
|
|
class ImplicitNumber extends Implicit { arg: number; }
|
|
|
|
(new ImplicitNumber().val: string) // error: number ~> string
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
class Generic<X> {
|
|
clone(): Generic<X> {
|
|
return this;
|
|
}
|
|
}
|
|
|
|
class Implicit<X> {
|
|
arg: X;
|
|
val: X;
|
|
}
|
|
class ImplicitNumber extends Implicit {
|
|
arg: number;
|
|
}
|
|
|
|
(new ImplicitNumber.val: string); // error: number ~> string"
|
|
`;
|
|
|
|
exports[`test import.js 1`] = `
|
|
"// Check that imports are handled properly with this types
|
|
|
|
import { A1 } from \'./export\';
|
|
import type { A2 } from \'./export\';
|
|
import { A3 } from \'./export\';
|
|
|
|
class B1 extends A1 {
|
|
foo(): B1 { return new B1(); } // error
|
|
}
|
|
|
|
(new B1().bar(): B1); // OK
|
|
|
|
class B3<X> extends A3<X> {
|
|
foo(): B3<X> { return new B3(); } // error
|
|
}
|
|
|
|
(new B3().bar(): B3<*>); // OK
|
|
(new B3().qux(0): string); // error
|
|
|
|
(new B3().bar(): A2<*>); // OK
|
|
((new B3().bar(): B3<string>): A2<number>); // error
|
|
((new B3(): A2<number>).qux(0): string); // error
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Check that imports are handled properly with this types
|
|
|
|
import {A1} from \"./export\";
|
|
import type {A2} from \"./export\";
|
|
import {A3} from \"./export\";
|
|
|
|
class B1 extends A1 {
|
|
foo(): B1 {
|
|
return new B1;
|
|
} // error
|
|
}
|
|
|
|
(new B1.bar(): B1);
|
|
// OK
|
|
class B3<X> extends A3<X> {
|
|
foo(): B3<X> {
|
|
return new B3;
|
|
} // error
|
|
}
|
|
|
|
(new B3.bar(): B3<*>);
|
|
// OK
|
|
(new B3.qux(0): string);
|
|
// error
|
|
(new B3.bar(): A2<*>);
|
|
// OK
|
|
((new B3.bar(): B3<string>): A2<number>);
|
|
// error
|
|
((new B3: A2<number>).qux(0): string); // error"
|
|
`;
|
|
|
|
exports[`test interface.js 1`] = `
|
|
"interface I { xs: Array<this>; }
|
|
interface J { f(): J; }
|
|
class C {
|
|
xs: Array<C>;
|
|
f(): C { return this; }
|
|
}
|
|
function foo(c: C): I { return c; }
|
|
function bar(c: C): J { return c; }
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
interface I { xs: Array<this> }
|
|
interface J { f(): J }
|
|
class C {
|
|
xs: Array<C>;
|
|
f(): C {
|
|
return this;
|
|
}
|
|
}
|
|
function foo(c: C): I {
|
|
return c;
|
|
}
|
|
function bar(c: C): J {
|
|
return c;
|
|
}"
|
|
`;
|
|
|
|
exports[`test lib_client.js 1`] = `
|
|
"(new DoublyLinkedList().prev(): DoublyLinkedList);
|
|
(new DoublyLinkedList().next(): DoublyLinkedList)
|
|
|
|
var MiniImmutable = require(\"mini-immutable\");
|
|
class C {
|
|
map: MiniImmutable.OrderedMap<number,string>;
|
|
update() {
|
|
this.map = this.map.set(0,\"\");
|
|
}
|
|
}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
(new DoublyLinkedList.prev(): DoublyLinkedList);
|
|
(new DoublyLinkedList.next(): DoublyLinkedList);
|
|
|
|
var MiniImmutable = require(\"mini-immutable\");
|
|
class C {
|
|
map: MiniImmutable.OrderedMap<number, string>;
|
|
update() {
|
|
this.map = this.map.set(0, \"\");
|
|
}
|
|
}"
|
|
`;
|
|
|
|
exports[`test self.js 1`] = `
|
|
"class A {
|
|
foo() { return this; } // return of foo is not annotated to get around
|
|
// substituting this below
|
|
bar(): this { return new A().foo(); } // same as returning : A, so error
|
|
qux(): this { return this.bar(); } // OK (don\'t cascade errors)
|
|
}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
class A {
|
|
foo() {
|
|
return this;
|
|
}
|
|
// return of foo is not annotated to get around
|
|
// substituting this below
|
|
bar(): this {
|
|
return new A.foo();
|
|
}
|
|
// same as returning : A, so error
|
|
qux(): this {
|
|
return this.bar();
|
|
} // OK (don\'t cascade errors)
|
|
}"
|
|
`;
|
|
|
|
exports[`test statics.js 1`] = `
|
|
"// supporting \`this\` type in statics
|
|
|
|
class A {
|
|
static make(): this { // factory method, whose return type \`this\` (still)
|
|
// describes instances of A or subclasses of A: the
|
|
// meaning of the \`this\` type is not changed simply by
|
|
// switching into a static context
|
|
return new this; // but in a static context, the value \`this\` is bound to
|
|
// the class, instead of instances of the class
|
|
}
|
|
}
|
|
class B extends A { } // inherits statics method too, with \`this\` bound to the class
|
|
|
|
(A.make(): A); // OK
|
|
(B.make(): B); // OK
|
|
(B.make(): A); // OK
|
|
(A.make(): B); // error
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// supporting \`this\` type in statics
|
|
|
|
class A {
|
|
static make(): this {
|
|
// factory method, whose return type \`this\` (still)
|
|
// describes instances of A or subclasses of A: the
|
|
// meaning of the \`this\` type is not changed simply by
|
|
// switching into a static context
|
|
return new this; // but in a static context, the value \`this\` is bound to
|
|
// the class, instead of instances of the class
|
|
}
|
|
}
|
|
class B extends A {}
|
|
// inherits statics method too, with \`this\` bound to the class
|
|
(A.make(): A);
|
|
// OK
|
|
(B.make(): B);
|
|
// OK
|
|
(B.make(): A);
|
|
// OK
|
|
(A.make(): B); // error"
|
|
`;
|
|
|
|
exports[`test test.js 1`] = `
|
|
"// Examples without \`this\` types (compare with examples below)
|
|
|
|
class Base {
|
|
foo() { return this; }
|
|
qux() { return new Base; }
|
|
|
|
bar() { return this; }
|
|
bar_caller() { return this.bar(); }
|
|
}
|
|
|
|
class Inherit extends Base { }
|
|
|
|
class Override extends Base {
|
|
foo() { return this; } // OK
|
|
qux() { return this; } // OK, too
|
|
|
|
bar() { return new Override; } // OK (cf. error below)
|
|
}
|
|
|
|
class InheritOverride extends Override { }
|
|
|
|
(new Inherit().foo(): Base);
|
|
(new Inherit().foo(): Inherit); // error (cf. OK below)
|
|
((new Inherit(): Base).foo(): Base);
|
|
(new Override().foo(): Base);
|
|
(new Override().foo(): Override); // OK
|
|
((new Override(): Base).foo(): Base);
|
|
|
|
(new InheritOverride().bar_caller(): InheritOverride); // error
|
|
// blame flips below
|
|
|
|
// Examples with \`this\` types (compare with examples above)
|
|
|
|
class Base2 {
|
|
foo(): this { return this; }
|
|
qux(): Base2 { return new Base2; }
|
|
|
|
bar(): this { return this; }
|
|
bar_caller(): this { return this.bar(); }
|
|
|
|
corge(that: this) { }
|
|
grault(that: Base2) { }
|
|
}
|
|
|
|
class Inherit2 extends Base2 { }
|
|
|
|
class Override2 extends Base2 {
|
|
foo(): this { return this; } // OK
|
|
qux(): this { return this; } // OK, too
|
|
|
|
bar(): Override2 { return new Override2; } // error (cf. OK above)
|
|
// see exploit below
|
|
|
|
corge(that: this) { } // error
|
|
// see exploit below
|
|
grault(that: this) { } // error, too
|
|
}
|
|
|
|
class InheritOverride2 extends Override2 { }
|
|
|
|
(new Inherit2().foo(): Base2);
|
|
(new Inherit2().foo(): Inherit2); // OK (cf. error above)
|
|
((new Inherit2(): Base2).foo(): Base2);
|
|
(new Override2().foo(): Base2);
|
|
(new Override2().foo(): Override2); // OK
|
|
((new Override2(): Base2).foo(): Base2);
|
|
|
|
(new InheritOverride2().bar_caller(): InheritOverride2); // exploits error above
|
|
|
|
(new Override2(): Base2).corge(new Base2()); // exploits error above
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Examples without \`this\` types (compare with examples below)
|
|
|
|
class Base {
|
|
foo() {
|
|
return this;
|
|
}
|
|
qux() {
|
|
return new Base;
|
|
}
|
|
|
|
bar() {
|
|
return this;
|
|
}
|
|
bar_caller() {
|
|
return this.bar();
|
|
}
|
|
}
|
|
|
|
class Inherit extends Base {}
|
|
|
|
class Override extends Base {
|
|
foo() {
|
|
return this;
|
|
}
|
|
// OK
|
|
qux() {
|
|
return this;
|
|
}
|
|
// OK, too
|
|
bar() {
|
|
return new Override;
|
|
} // OK (cf. error below)
|
|
}
|
|
|
|
class InheritOverride extends Override {}
|
|
|
|
(new Inherit.foo(): Base);
|
|
(new Inherit.foo(): Inherit);
|
|
// error (cf. OK below)
|
|
((new Inherit: Base).foo(): Base);
|
|
(new Override.foo(): Base);
|
|
(new Override.foo(): Override);
|
|
// OK
|
|
((new Override: Base).foo(): Base);
|
|
|
|
(new InheritOverride.bar_caller(): InheritOverride);
|
|
// error
|
|
// blame flips below
|
|
// Examples with \`this\` types (compare with examples above)
|
|
class Base2 {
|
|
foo(): this {
|
|
return this;
|
|
}
|
|
qux(): Base2 {
|
|
return new Base2;
|
|
}
|
|
|
|
bar(): this {
|
|
return this;
|
|
}
|
|
bar_caller(): this {
|
|
return this.bar();
|
|
}
|
|
|
|
corge(that: this) {}
|
|
grault(that: Base2) {}
|
|
}
|
|
|
|
class Inherit2 extends Base2 {}
|
|
|
|
class Override2 extends Base2 {
|
|
foo(): this {
|
|
return this;
|
|
}
|
|
// OK
|
|
qux(): this {
|
|
return this;
|
|
}
|
|
// OK, too
|
|
bar(): Override2 {
|
|
return new Override2;
|
|
}
|
|
// error (cf. OK above)
|
|
// see exploit below
|
|
corge(that: this) {}
|
|
// error
|
|
// see exploit below
|
|
grault(that: this) {} // error, too
|
|
}
|
|
|
|
class InheritOverride2 extends Override2 {}
|
|
|
|
(new Inherit2.foo(): Base2);
|
|
(new Inherit2.foo(): Inherit2);
|
|
// OK (cf. error above)
|
|
((new Inherit2: Base2).foo(): Base2);
|
|
(new Override2.foo(): Base2);
|
|
(new Override2.foo(): Override2);
|
|
// OK
|
|
((new Override2: Base2).foo(): Base2);
|
|
|
|
(new InheritOverride2.bar_caller(): InheritOverride2);
|
|
// exploits error above
|
|
(new Override2: Base2).corge(new Base2); // exploits error above"
|
|
`;
|