Add special case for comment at top of file; regenerate snapshots

master
James Long 2017-01-09 21:49:06 -05:00
parent 74fc539e1a
commit a4643f1bae
365 changed files with 7437 additions and 6418 deletions

View File

@ -79,7 +79,8 @@ function decorateComment(node, comment, text) {
if (locStart(child) - locStart(comment) <= 0 && if (locStart(child) - locStart(comment) <= 0 &&
locEnd(comment) - locEnd(child) <= 0) { locEnd(comment) - locEnd(child) <= 0) {
// The comment is completely contained by this child node. // The comment is completely contained by this child node.
decorateComment(comment.enclosingNode = child, comment, text); comment.enclosingNode = child;
decorateComment(child, comment, text);
return; // Abandon the binary search at this level. return; // Abandon the binary search at this level.
} }
@ -163,7 +164,7 @@ exports.attach = function(comments, ast, text) {
addDanglingComment(en, comment); addDanglingComment(en, comment);
} else { } else {
throw new Error("AST contains no nodes at all?"); // throw new Error("AST contains no nodes at all?");
} }
}); });
@ -271,9 +272,12 @@ function printTrailingComment(commentPath, print, options) {
exports.printComments = function(path, print, options) { exports.printComments = function(path, print, options) {
var value = path.getValue(); var value = path.getValue();
var parent = path.getParentNode();
var printed = print(path); var printed = print(path);
var comments = n.Node.check(value) && var comments = n.Node.check(value) &&
types.getFieldValue(value, "comments"); types.getFieldValue(value, "comments");
var isFirstInProgram = n.Program.check(parent) &&
parent.body[0] === value;
if (!comments || comments.length === 0) { if (!comments || comments.length === 0) {
return printed; return printed;
@ -291,6 +295,15 @@ exports.printComments = function(path, print, options) {
comment.type === "Block" || comment.type === "Block" ||
comment.type === "CommentBlock"))) { comment.type === "CommentBlock"))) {
leadingParts.push(printLeadingComment(commentPath, print)); leadingParts.push(printLeadingComment(commentPath, print));
// Support a special case where a comment exists at the very top
// of the file. Allow the user to add spacing between that file
// and any code beneath it.
if(isFirstInProgram &&
util.newlineExistsAfter(options.originalText, util.locEnd(comment))) {
leadingParts.push(hardline);
}
} else if (trailing) { } else if (trailing) {
trailingParts.push(printTrailingComment(commentPath, print, options)); trailingParts.push(printTrailingComment(commentPath, print, options));
} }

View File

@ -1551,8 +1551,6 @@ function genericPrintNoParens(path, options, print) {
} }
function printStatementSequence(path, options, print) { function printStatementSequence(path, options, print) {
let inClassBody = namedTypes.ClassBody &&
namedTypes.ClassBody.check(path.getParentNode());
let printed = []; let printed = [];
path.map(function(stmtPath, i) { path.map(function(stmtPath, i) {
@ -1571,11 +1569,13 @@ function printStatementSequence(path, options, print) {
} }
const stmtPrinted = print(stmtPath); const stmtPrinted = print(stmtPath);
const text = options.originalText;
const parts = []; const parts = [];
parts.push(stmtPrinted); parts.push(stmtPrinted);
if (shouldAddSpacing(stmt, options) && !isLastStatement(stmtPath)) { if (util.newlineExistsAfter(text, util.locEnd(stmt)) &&
!isLastStatement(stmtPath)) {
parts.push(hardline); parts.push(hardline);
} }
@ -2008,11 +2008,6 @@ function nodeStr(str, options) {
} }
} }
function shouldAddSpacing(node, options) {
const text = options.originalText;
return util.newlineExistsAfter(text, util.locEnd(node));
}
function isFirstStatement(path) { function isFirstStatement(path) {
const parent = path.getParentNode(); const parent = path.getParentNode();
const node = path.getValue(); const node = path.getValue();

View File

@ -12,13 +12,13 @@ function foo() {
break; break;
} }
} }
function bar() { function bar() {
L: L:
do { do {
continue L; continue L;
} while (false); } while (false);
} }"
"
`; `;
exports[`test return.js 1`] = ` exports[`test return.js 1`] = `
@ -35,6 +35,5 @@ function foo() {
if (x == null) if (x == null)
return; return;
bar(x); bar(x);
} }"
"
`; `;

View File

@ -60,45 +60,54 @@ var zer : null = null;
function foobar(n : ?number) : number | null | void { return n; } function foobar(n : ?number) : number | null | void { return n; }
function barfoo(n : number | null | void) : ?number { return n; } function barfoo(n : number | null | void) : ?number { return n; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// array sugar
// param type annos are strict UBs like var type annos
// error
// another error on param UB, more typical of www (mis)use-cases
// this one cribbed from API.atlas.js
// error below, since we\'re assigning elements to batchRequests
// which lack a path property.
// just assign result to new var instead of reassigning to param.
// Transform the requests to the format the Graph API expects.
// ...
function foo(str: string, i: number): string { function foo(str: string, i: number): string {
return str; return str;
} }
var bar: (str: number, i: number) => string = foo; var bar: (str: number, i: number) => string = foo;
var qux = function(str: string, i: number): number { var qux = function(str: string, i: number): number {
return foo(str, i); return foo(str, i);
}; };
var obj: { str: string, i: number, j: boolean } = { var obj: { str: string, i: number, j: boolean } = {
str: \"...\", str: \"...\",
i: \"...\", i: \"...\",
k: false k: false
}; };
var arr: Array<number> = [ 1, 2, \"...\" ]; var arr: Array<number> = [ 1, 2, \"...\" ];
// array sugar
var array: number[] = [ 1, 2, \"...\" ]; var array: number[] = [ 1, 2, \"...\" ];
var matrix: number[][] = [ [ 1, 2 ], [ 3, 4 ] ]; var matrix: number[][] = [ [ 1, 2 ], [ 3, 4 ] ];
var matrix_parens: number[][] = matrix; var matrix_parens: number[][] = matrix;
var nullable_array: ?(number[]) = null; var nullable_array: ?(number[]) = null;
var nullable_array_parens: ?(number[]) = nullable_array; var nullable_array_parens: ?(number[]) = nullable_array;
var array_of_nullable: (?number)[] = [ null, 3 ]; var array_of_nullable: (?number)[] = [ null, 3 ];
var array_of_tuple: [number, string][] = [ [ 0, \"foo\" ], [ 1, \"bar\" ] ]; var array_of_tuple: [number, string][] = [ [ 0, \"foo\" ], [ 1, \"bar\" ] ];
var array_of_tuple_parens: [number, string][] = array_of_tuple; var array_of_tuple_parens: [number, string][] = array_of_tuple;
type ObjType = { \"bar-foo\": string, \"foo-bar\": number }; type ObjType = { \"bar-foo\": string, \"foo-bar\": number };
var test_obj: ObjType = { \"bar-foo\": \"23\" }; var test_obj: ObjType = { \"bar-foo\": \"23\" };
// param type annos are strict UBs like var type annos
function param_anno(n: number): void { function param_anno(n: number): void {
n = \"hey\"; n = \"hey\"; // error
} }
// another error on param UB, more typical of www (mis)use-cases
// this one cribbed from API.atlas.js
function param_anno2( function param_anno2(
batchRequests: Array<{ method: string, path: string, params: ?Object }> batchRequests: Array<{ method: string, path: string, params: ?Object }>
): void { ): void {
// error below, since we\'re assigning elements to batchRequests
// which lack a path property.
// just assign result to new var instead of reassigning to param.
// Transform the requests to the format the Graph API expects.
batchRequests = batchRequests.map(request => { batchRequests = batchRequests.map(request => {
return { return {
method: request.method, method: request.method,
@ -106,16 +115,19 @@ function param_anno2(
relative_url: request.path relative_url: request.path
}; };
}); });
// ...
} }
var toz: null = 3; var toz: null = 3;
var zer: null = null; var zer: null = null;
function foobar(n: ?number): number | null | void { function foobar(n: ?number): number | null | void {
return n; return n;
} }
function barfoo(n: number | null | void): ?number { function barfoo(n: number | null | void): ?number {
return n; return n;
} }"
"
`; `;
exports[`test forward_ref.js 1`] = ` exports[`test forward_ref.js 1`] = `
@ -134,24 +146,23 @@ function foo() {
class MyClass { } // looked up above class MyClass { } // looked up above
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// forward ref ok, null ~> class error
// forward ref ok, null ~> class error
// looked up above
// ok (no confusion across scopes)
// looked up above
let myClassInstance: MyClass = null; let myClassInstance: MyClass = null;
// forward ref ok, null ~> class error
function bar(): MyClass { function bar(): MyClass {
return null; return null; // forward ref ok, null ~> class error
} }
class MyClass {} class MyClass {}
// looked up above
function foo() { function foo() {
let myClassInstance: MyClass = mk(); let myClassInstance: MyClass = mk();
// ok (no confusion across scopes)
function mk() { function mk() {
return new MyClass(); return new MyClass();
} }
class MyClass {}
} class MyClass {} // looked up above
" }"
`; `;
exports[`test issue-530.js 1`] = ` exports[`test issue-530.js 1`] = `
@ -160,8 +171,8 @@ exports[`test issue-530.js 1`] = `
module.exports = foo; module.exports = foo;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function foo(...args: any) {} function foo(...args: any) {}
module.exports = foo;
" module.exports = foo;"
`; `;
exports[`test leak.js 1`] = ` exports[`test leak.js 1`] = `
@ -189,6 +200,7 @@ function bar(y: MyObj): string {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** @flow */ /** @flow */
/* This test documents an example we ran into of a type annotation leaking. /* This test documents an example we ran into of a type annotation leaking.
* *
* When foo() calls bar(), we should make sure the type of x matches the type * When foo() calls bar(), we should make sure the type of x matches the type
@ -199,14 +211,16 @@ function bar(y: MyObj): string {
* and type checking the body of bar() using the stricter dictionary type, * and type checking the body of bar() using the stricter dictionary type,
* leading to an error. * leading to an error.
*/ */
type MyObj = Object; type MyObj = Object;
function foo(x: { [key: string]: mixed }) { function foo(x: { [key: string]: mixed }) {
bar(x); bar(x);
} }
function bar(y: MyObj): string { function bar(y: MyObj): string {
return y.foo; return y.foo;
} }"
"
`; `;
exports[`test other.js 1`] = ` exports[`test other.js 1`] = `
@ -214,8 +228,7 @@ exports[`test other.js 1`] = `
module.exports = (C: any); module.exports = (C: any);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class C {} class C {}
module.exports = (C: any); module.exports = (C: any);"
"
`; `;
exports[`test scope.js 1`] = ` exports[`test scope.js 1`] = `
@ -244,13 +257,16 @@ class Foo<A> {
} }
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// hypothetical immutable map
type Merge<T> = (a: T, b: T) => T; type Merge<T> = (a: T, b: T) => T;
// hypothetical immutable map
declare class Map<K, V> { declare class Map<K, V> {
(): Map<K, V>, (): Map<K, V>,
insertWith(fn: Merge<V>, k: K, v: V): Map<K, V> insertWith(fn: Merge<V>, k: K, v: V): Map<K, V>
} }
declare function foldr<A, B>(fn: (a: A, b: B) => B, b: B, as: A[]): B; declare function foldr<A, B>(fn: (a: A, b: B) => B, b: B, as: A[]): B;
function insertMany<K, V>( function insertMany<K, V>(
merge: Merge<V>, merge: Merge<V>,
vs: [K, V][], vs: [K, V][],
@ -261,14 +277,14 @@ function insertMany<K, V>(
} }
return foldr(f, m, vs); return foldr(f, m, vs);
} }
class Foo<A> { class Foo<A> {
bar<B>() { bar<B>() {
return function<C>(a: A, b: B, c: C): void { return function<C>(a: A, b: B, c: C): void {
([ a, b, c ]: [A, B, C]); ([ a, b, c ]: [A, B, C]);
}; };
} }
} }"
"
`; `;
exports[`test test.js 1`] = ` exports[`test test.js 1`] = `
@ -276,6 +292,5 @@ exports[`test test.js 1`] = `
((0: C): string); ((0: C): string);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var C = require(\"./other\"); var C = require(\"./other\");
((0: C): string); ((0: C): string);"
"
`; `;

View File

@ -10,13 +10,14 @@ export default class {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
type T = any; type T = any;
export default class { export default class {
p: T; p: T;
constructor() { constructor() {
this.p = 0; this.p = 0;
} }
} }"
"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
@ -26,10 +27,9 @@ class B extends A {
p: string; // OK, string ~> any p: string; // OK, string ~> any
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// OK, string ~> any
import A from \"./A\"; import A from \"./A\";
class B extends A { class B extends A {
p: string; p: string; // OK, string ~> any
} }"
"
`; `;

View File

@ -18,14 +18,16 @@ export default class {
* @providesModule A * @providesModule A
* @flow * @flow
*/ */
import type T from \"T\"; import type T from \"T\";
export default class { export default class {
p: T; p: T;
constructor() { constructor() {
this.p = 0; this.p = 0;
} }
} }"
"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
@ -42,12 +44,12 @@ class B extends A {
/** /**
* @flow * @flow
*/ */
// OK, string ~> any
import A from \"A\"; import A from \"A\";
class B extends A { class B extends A {
p: string; p: string; // OK, string ~> any
} }"
"
`; `;
exports[`test T.js 1`] = ` exports[`test T.js 1`] = `
@ -55,9 +57,5 @@ exports[`test T.js 1`] = `
* @providesModule T * @providesModule T
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @providesModule T
*/
" "
`; `;

View File

@ -10,6 +10,7 @@ var y:string = bar(0);
var z:string = qux(0); var z:string = qux(0);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
function foo(x: any): any { function foo(x: any): any {
return x; return x;
} }
@ -19,10 +20,10 @@ function bar(x: any): mixed {
function qux(x: mixed): any { function qux(x: mixed): any {
return x; return x;
} }
var x: string = foo(0); var x: string = foo(0);
var y: string = bar(0); var y: string = bar(0);
var z: string = qux(0); var z: string = qux(0);"
"
`; `;
exports[`test anyexportflowfile.js 1`] = ` exports[`test anyexportflowfile.js 1`] = `
@ -31,8 +32,8 @@ exports[`test anyexportflowfile.js 1`] = `
module.exports = ((x: any) => x: any); module.exports = ((x: any) => x: any);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
module.exports = ((x: any) => x: any);
" module.exports = ((x: any) => x: any);"
`; `;
exports[`test flowfixme.js 1`] = ` exports[`test flowfixme.js 1`] = `
@ -62,26 +63,27 @@ var w:string = baz(0);
@flow @flow
*/ */
// no param // no param
// param (info only)
// ...params are still checked. unknown type
function foo(x: $FlowFixMe): $FlowFixMe { function foo(x: $FlowFixMe): $FlowFixMe {
return x; return x;
} }
function bar(x: $FlowFixMe): mixed { function bar(x: $FlowFixMe): mixed {
return x; return x;
} }
// param (info only)
function qux(x: $FlowFixMe<number>): $FlowFixMe<number> { function qux(x: $FlowFixMe<number>): $FlowFixMe<number> {
return x; return x;
} }
// ...params are still checked. unknown type
function baz(x: $FlowFixMe<nnumber>): $FlowFixMe<number> { function baz(x: $FlowFixMe<nnumber>): $FlowFixMe<number> {
return x; return x;
} }
var x: string = foo(0); var x: string = foo(0);
var y: string = bar(0); var y: string = bar(0);
var z: string = qux(0); var z: string = qux(0);
var w: string = baz(0); var w: string = baz(0);"
"
`; `;
exports[`test flowissue.js 1`] = ` exports[`test flowissue.js 1`] = `
@ -111,26 +113,27 @@ var w:string = baz(0);
@flow @flow
*/ */
// no param // no param
// param (info only)
// ...params are still checked. unknown type
function foo(x: $FlowIssue): $FlowIssue { function foo(x: $FlowIssue): $FlowIssue {
return x; return x;
} }
function bar(x: $FlowIssue): mixed { function bar(x: $FlowIssue): mixed {
return x; return x;
} }
// param (info only)
function qux(x: $FlowIssue<number>): $FlowIssue<number> { function qux(x: $FlowIssue<number>): $FlowIssue<number> {
return x; return x;
} }
// ...params are still checked. unknown type
function baz(x: $FlowIssue<nnumber>): $FlowIssue<number> { function baz(x: $FlowIssue<nnumber>): $FlowIssue<number> {
return x; return x;
} }
var x: string = foo(0); var x: string = foo(0);
var y: string = bar(0); var y: string = bar(0);
var z: string = qux(0); var z: string = qux(0);
var w: string = baz(0); var w: string = baz(0);"
"
`; `;
exports[`test nonflowfile.js 1`] = ` exports[`test nonflowfile.js 1`] = `
@ -139,8 +142,8 @@ exports[`test nonflowfile.js 1`] = `
module.exports = (x) => x; module.exports = (x) => x;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @noflow // @noflow
module.exports = x => x;
" module.exports = x => x;"
`; `;
exports[`test propagate.js 1`] = ` exports[`test propagate.js 1`] = `
@ -171,28 +174,30 @@ function bar2(x: mixed) {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// should be able to select first case and error
declare class C { declare class C {
bar(n1: number, n2: number): number, bar(n1: number, n2: number): number,
bar(s1: string, s2: string): string bar(s1: string, s2: string): string
} }
function foo(c: C, x: any): string { function foo(c: C, x: any): string {
let y = x.y; let y = x.y;
return c.bar(0, y); return c.bar(0, y); // should be able to select first case and error
} }
var any_fun1 = require(\"./nonflowfile\"); var any_fun1 = require(\"./nonflowfile\");
function bar1(x: mixed) { function bar1(x: mixed) {
if (any_fun1(x)) { if (any_fun1(x)) {
(x: boolean); (x: boolean);
} }
} }
var any_fun2 = require(\"./anyexportflowfile\"); var any_fun2 = require(\"./anyexportflowfile\");
function bar2(x: mixed) { function bar2(x: mixed) {
if (any_fun2(x)) { if (any_fun2(x)) {
(x: boolean); (x: boolean);
} }
} }"
"
`; `;
exports[`test reach.js 1`] = ` exports[`test reach.js 1`] = `
@ -215,11 +220,12 @@ function foo(o: ?AsyncRequest) {
* type annotations. Here we test propagation of any through the * type annotations. Here we test propagation of any through the
* annotation - without it, the body of the if will be unreachable * annotation - without it, the body of the if will be unreachable
*/ */
type AsyncRequest = any; type AsyncRequest = any;
function foo(o: ?AsyncRequest) { function foo(o: ?AsyncRequest) {
if (o) { if (o) {
var n: number = o; var n: number = o;
} }
} }"
"
`; `;

View File

@ -92,116 +92,118 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @providesModule Arith */ /* @providesModule Arith */
// error
// error
// error
// test MaybeT(NumT)
// test OptionalT(NumT)
// test OptionalT(MaybeT(NumT))
// === 0
// === NaN
// === 1
// === 1
// === NaN
// === NaN
// === 1
// === 1
// === NaN
// === NaN
// error
// error
// error
// error
// error
// error
// error
// error
// error
// error
// error
// error
// error
// when one side is a string or number and the other is invalid, we
// assume you are expecting a string or number (respectively), rather than
// erroring twice saying number !~> string and obj !~> string.
// error: object !~> number
// error: object !~> number
// error: object !~> string
// error: object !~> string
// ok
// ok
// error, string ~> empty
// error, string ~> empty
function num(x: number) {} function num(x: number) {}
function str(x: string) {} function str(x: string) {}
function foo() { function foo() {
var x = 0; var x = 0;
var y = \"...\"; var y = \"...\";
var z = {}; var z = {};
num(x + x); num(x + x);
num(x + y); num(x + y);
// error
str(x + y); str(x + y);
str(x + x); str(x + x);
str(z + y); // error
str(z + y); // error
} }
// test MaybeT(NumT)
function bar0(x: ?number, y: number) { function bar0(x: ?number, y: number) {
num(x + y); num(x + y);
} }
function bar1(x: number, y: ?number) { function bar1(x: number, y: ?number) {
num(x + y); num(x + y);
} }
// test OptionalT(NumT)
function bar2(x?: number, y: number) { function bar2(x?: number, y: number) {
num(x + y); num(x + y);
} }
function bar3(x: number, y?: number) { function bar3(x: number, y?: number) {
num(x + y); num(x + y);
} }
// test OptionalT(MaybeT(NumT))
function bar4(x?: ?number, y: number) { function bar4(x?: ?number, y: number) {
num(x + y); num(x + y);
} }
function bar5(x: number, y?: ?number) { function bar5(x: number, y?: ?number) {
num(x + y); num(x + y);
} }
num(null + null); num(null + null);
// === 0
num(undefined + undefined); num(undefined + undefined);
// === NaN
num(null + 1); num(null + 1);
// === 1
num(1 + null); num(1 + null);
// === 1
num(undefined + 1); num(undefined + 1);
// === NaN
num(1 + undefined); num(1 + undefined);
// === NaN
num(null + true); num(null + true);
// === 1
num(true + null); num(true + null);
// === 1
num(undefined + true); num(undefined + true);
// === NaN
num(true + undefined); num(true + undefined);
// === NaN
str(\"foo\" + true); str(\"foo\" + true);
// error
str(true + \"foo\"); str(true + \"foo\");
// error
str(\"foo\" + null); str(\"foo\" + null);
// error
str(null + \"foo\"); str(null + \"foo\");
// error
str(\"foo\" + undefined); str(\"foo\" + undefined);
// error
str(undefined + \"foo\"); str(undefined + \"foo\");
// error
let tests = [ let tests = [
function(x: mixed, y: mixed) { function(x: mixed, y: mixed) {
x + y; x + y;
// error
x + 0; x + 0;
// error
0 + x; 0 + x;
// error
x + \"\"; x + \"\";
// error
\"\" + x; \"\" + x;
// error
x + {}; x + {};
({}) + x; // error
({}) + x; // error
}, },
// when one side is a string or number and the other is invalid, we
// assume you are expecting a string or number (respectively), rather than
// erroring twice saying number !~> string and obj !~> string.
function() { function() {
(1 + {}: number); (1 + {}: number);
// error: object !~> number
({} + 1: number); ({} + 1: number);
// error: object !~> number
(\"1\" + {}: string); (\"1\" + {}: string);
({} + \"1\": string); // error: object !~> string
({} + \"1\": string); // error: object !~> string
}, },
function(x: any, y: number, z: string) { function(x: any, y: number, z: string) {
(x + y: string); (x + y: string);
// ok
(y + x: string); (y + x: string);
// ok
(x + z: empty); (x + z: empty);
(z + x: empty); // error, string ~> empty
(z + x: empty); // error, string ~> empty
} }
]; ];"
"
`; `;
exports[`test exponent.js 1`] = ` exports[`test exponent.js 1`] = `
@ -218,15 +220,16 @@ y **= 2; // error
(-2) ** 2; (-2) ** 2;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error
let x: number = 2 ** 3; let x: number = 2 ** 3;
x **= 4; x **= 4;
let y: string = \"123\"; let y: string = \"123\";
y **= 2; y **= 2;
// error
1 + 2 ** 3 + 4; 1 + 2 ** 3 + 4;
2 ** 2; 2 ** 2;
(-2) ** 2; (-2) ** 2;"
"
`; `;
exports[`test generic.js 1`] = ` exports[`test generic.js 1`] = `
@ -239,27 +242,26 @@ function f<A,B>(a: A, b: B): B {return a + b; } // error
function f<A,B>(a: A, b: B): B {return b + a; } // error function f<A,B>(a: A, b: B): B {return b + a; } // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error
// error
// error
// error
// error
function f<A>(a: A): A { function f<A>(a: A): A {
return a + a; return a + a;
} }
// error
function f<A, B>(a: A, b: B): A { function f<A, B>(a: A, b: B): A {
return a + b; return a + b;
} }
// error
function f<A, B>(a: A, b: B): A { function f<A, B>(a: A, b: B): A {
return b + a; return b + a;
} }
// error
function f<A, B>(a: A, b: B): B { function f<A, B>(a: A, b: B): B {
return a + b; return a + b;
} }
// error
function f<A, B>(a: A, b: B): B { function f<A, B>(a: A, b: B): B {
return b + a; return b + a;
} } // error"
"
`; `;
exports[`test mult.js 1`] = ` exports[`test mult.js 1`] = `
@ -277,15 +279,17 @@ let y: string = \"123\";
y *= 2; // error y *= 2; // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error
function num(x: number) {} function num(x: number) {}
num(null * 1); num(null * 1);
num(1 * null); num(1 * null);
let x: number = 2 * 3; let x: number = 2 * 3;
x *= 4; x *= 4;
let y: string = \"123\"; let y: string = \"123\";
y *= 2; y *= 2; // error"
"
`; `;
exports[`test relational.js 1`] = ` exports[`test relational.js 1`] = `
@ -321,43 +325,44 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error
// error
// error
// error
// error
// error
// error
// 2 errors: null !~> number; undefined !~> number
// 2 errors: null !~> number; undefined !~> number
// error
// error
// error
// error
1 < 2; 1 < 2;
1 < \"foo\"; 1 < \"foo\";
// error
\"foo\" < 1; \"foo\" < 1;
// error
\"foo\" < \"bar\"; \"foo\" < \"bar\";
1 < { foo: 1 }; 1 < { foo: 1 };
// error
({ foo: 1 }) < 1; ({ foo: 1 }) < 1;
// error
({ foo: 1 }) < { foo: 1 }; ({ foo: 1 }) < { foo: 1 };
// error
\"foo\" < { foo: 1 }; \"foo\" < { foo: 1 };
// error
({ foo: 1 }) < \"foo\"; ({ foo: 1 }) < \"foo\";
// error
var x = (null: ?number); var x = (null: ?number);
1 < x; 1 < x;
// 2 errors: null !~> number; undefined !~> number
x < 1; x < 1;
// 2 errors: null !~> number; undefined !~> number
null < null; null < null;
// error
undefined < null; undefined < null;
// error
null < undefined; null < undefined;
// error
undefined < undefined; undefined < undefined;
// error
NaN < 1; NaN < 1;
1 < NaN; 1 < NaN;
NaN < NaN; NaN < NaN;
let tests = [ let tests = [
function(x: any, y: number, z: string) { function(x: any, y: number, z: string) {
x > y; x > y;
x > z; x > z;
} }
]; ];"
"
`; `;

View File

@ -10,13 +10,14 @@ function filterOutSmall (arr: Array<?number>): Array<?number> {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
function filterOutVoids<T>(arr: Array<?T>): Array<T> { function filterOutVoids<T>(arr: Array<?T>): Array<T> {
return arr.filter(Boolean); return arr.filter(Boolean);
} }
function filterOutSmall(arr: Array<?number>): Array<?number> { function filterOutSmall(arr: Array<?number>): Array<?number> {
return arr.filter(num => num && num > 10); return arr.filter(num => num && num > 10);
} }"
"
`; `;
exports[`test test2.js 1`] = ` exports[`test test2.js 1`] = `
@ -37,6 +38,7 @@ const filteredItems = filterItems([\'foo\', \'b\', 1, 2]);
console.log(filteredItems); console.log(filteredItems);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
function filterItems(items: Array<string | number>): Array<string | number> { function filterItems(items: Array<string | number>): Array<string | number> {
return items.map(item => { return items.map(item => {
if (typeof item === \"string\") { if (typeof item === \"string\") {
@ -46,7 +48,8 @@ function filterItems(items: Array<string | number>): Array<string | number> {
} }
}).filter(Boolean); }).filter(Boolean);
} }
const filteredItems = filterItems([ \"foo\", \"b\", 1, 2 ]); const filteredItems = filterItems([ \"foo\", \"b\", 1, 2 ]);
console.log(filteredItems);
" console.log(filteredItems);"
`; `;

View File

@ -13,7 +13,7 @@ var B = [ ...A ];
var C = [ 1, 2, 3 ]; var C = [ 1, 2, 3 ];
B.sort((a, b) => a - b); B.sort((a, b) => a - b);
C.sort((a, b) => a - b); C.sort((a, b) => a - b);
var x: Array<string> = [ \"1\", \"2\" ]; var x: Array<string> = [ \"1\", \"2\" ];
var y: Array<string> = [ \"3\", ...x ]; var y: Array<string> = [ \"3\", ...x ];"
"
`; `;

View File

@ -58,27 +58,24 @@ function from_test() {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Error
/* Adapted from the following source:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
*/
/* Added later, because the above is insufficient */
// acc is element type of array when no init is provided
// error, string ~> number
// error, string ~> number
function foo(x: string) {} function foo(x: string) {}
var a = [ 0 ]; var a = [ 0 ];
var b = a.map(function(x) { var b = a.map(function(x) {
foo(x); foo(x);
return \"\" + x; return \"\" + x;
}); });
var c: number = a[0]; var c: number = a[0];
var d: number = b[0]; var d: number = b[0];
var e: Array<string> = a.reverse(); var e: Array<string> = a.reverse();
var f = [ \"\" ]; var f = [ \"\" ];
var g: number = f.map(function() { var g: number = f.map(function() {
return 0; return 0;
})[0]; })[0];
var h: Array<number> = [ 1, 2, 3 ]; var h: Array<number> = [ 1, 2, 3 ];
var i: Array<string> = [ \"a\", \"b\", \"c\" ]; var i: Array<string> = [ \"a\", \"b\", \"c\" ];
var j: Array<number | string> = h.concat(i); var j: Array<number | string> = h.concat(i);
@ -86,25 +83,37 @@ var k: Array<number> = h.concat(h);
var l: Array<number> = h.concat(1, 2, 3); var l: Array<number> = h.concat(1, 2, 3);
var m: Array<number | string> = h.concat(\"a\", \"b\", \"c\"); var m: Array<number | string> = h.concat(\"a\", \"b\", \"c\");
var n: Array<number> = h.concat(\"a\", \"b\", \"c\"); var n: Array<number> = h.concat(\"a\", \"b\", \"c\");
// Error
function reduce_test() { function reduce_test() {
/* Adapted from the following source:
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
*/
[ 0, 1, 2, 3, 4 ].reduce(function(previousValue, currentValue, index, array) { [ 0, 1, 2, 3, 4 ].reduce(function(previousValue, currentValue, index, array) {
return previousValue + currentValue + array[index]; return previousValue + currentValue + array[index];
}); });
[ 0, 1, 2, 3, 4 ].reduce( [ 0, 1, 2, 3, 4 ].reduce(
function(previousValue, currentValue, index, array) { function(previousValue, currentValue, index, array) {
return previousValue + currentValue + array[index]; return previousValue + currentValue + array[index];
}, },
10 10
); );
var total = [ 0, 1, 2, 3 ].reduce(function(a, b) { var total = [ 0, 1, 2, 3 ].reduce(function(a, b) {
return a + b; return a + b;
}); });
var flattened = [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ] ].reduce(function(a, b) { var flattened = [ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ] ].reduce(function(a, b) {
return a.concat(b); return a.concat(b);
}); });
/* Added later, because the above is insufficient */
// acc is element type of array when no init is provided
[ \"\" ].reduce((acc, str) => acc * str.length); [ \"\" ].reduce((acc, str) => acc * str.length);
[ \"\" ].reduceRight((acc, str) => acc * str.length); // error, string ~> number
[ \"\" ].reduceRight((acc, str) => acc * str.length); // error, string ~> number
} }
function from_test() { function from_test() {
var a: Array<string> = Array.from([ 1, 2, 3 ], function(val, index) { var a: Array<string> = Array.from([ 1, 2, 3 ], function(val, index) {
return index % 2 ? \"foo\" : String(val); return index % 2 ? \"foo\" : String(val);
@ -112,6 +121,5 @@ function from_test() {
var b: Array<string> = Array.from([ 1, 2, 3 ], function(val) { var b: Array<string> = Array.from([ 1, 2, 3 ], function(val) {
return String(val); return String(val);
}); });
} }"
"
`; `;

View File

@ -40,17 +40,22 @@ var abig2: Array<{x:number; y:number}> = [
module.exports = \"arrays\"; module.exports = \"arrays\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @providesModule Arrays */ /* @providesModule Arrays */
// for literals, composite element type is union of individuals
// note: test both tuple and non-tuple inferred literals
function foo(x: string) {} function foo(x: string) {}
var a = []; var a = [];
a[0] = 1; a[0] = 1;
a[1] = \"...\"; a[1] = \"...\";
foo(a[1]); foo(a[1]);
var y; var y;
a.forEach(x => y = x); a.forEach(x => y = x);
// for literals, composite element type is union of individuals
// note: test both tuple and non-tuple inferred literals
var alittle: Array<?number> = [ 0, 1, 2, 3, null ]; var alittle: Array<?number> = [ 0, 1, 2, 3, null ];
var abig: Array<?number> = [ 0, 1, 2, 3, 4, 5, 6, 8, null ]; var abig: Array<?number> = [ 0, 1, 2, 3, 4, 5, 6, 8, null ];
var abig2: Array<{ x: number, y: number }> = [ var abig2: Array<{ x: number, y: number }> = [
{ x: 0, y: 0 }, { x: 0, y: 0 },
{ x: 0, y: 0 }, { x: 0, y: 0 },
@ -70,8 +75,8 @@ var abig2: Array<{ x: number, y: number }> = [
{ x: 0, y: 0, c: 1 }, { x: 0, y: 0, c: 1 },
{ x: 0, y: 0, c: \"hey\" } { x: 0, y: 0, c: \"hey\" }
]; ];
module.exports = \"arrays\";
" module.exports = \"arrays\";"
`; `;
exports[`test numeric_elem.js 1`] = ` exports[`test numeric_elem.js 1`] = `
@ -83,12 +88,11 @@ var day = new Date;
arr[day] = 0; arr[day] = 0;
(arr[day]: string); // error: number ~> string (arr[day]: string); // error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Date instances are numeric (see Flow_js.numeric) and thus can index into
// arrays.
// error: number ~> string
var arr = []; var arr = [];
var day = new Date(); var day = new Date();
// Date instances are numeric (see Flow_js.numeric) and thus can index into
// arrays.
arr[day] = 0; arr[day] = 0;
(arr[day]: string); (arr[day]: string); // error: number ~> string"
"
`; `;

View File

@ -14,14 +14,14 @@ var ident = <T>(x: T): T => x;
/** /**
* @flow * @flow
*/ */
// Error!
// Error
var add = (x: number, y: number): number => x + y; var add = (x: number, y: number): number => x + y;
var bad = (x: number): string => x; var bad = (x: number): string => x;
// Error!
var ident = <T>(x: T): T => x; var ident = <T>(x: T): T => x;
(ident(1): number); (ident(1): number);
(ident(\"hi\"): number); (ident(\"hi\"): number); // Error"
"
`; `;
exports[`test arrows.js 1`] = ` exports[`test arrows.js 1`] = `
@ -36,15 +36,14 @@ exports[`test arrows.js 1`] = `
images[images.length - 1]; images[images.length - 1];
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//images = images.sort(function (a, b) { return a.width - b.width });
function selectBestEffortImageForWidth( function selectBestEffortImageForWidth(
maxWidth: number, maxWidth: number,
images: Array<Image> images: Array<Image>
): Image { ): Image {
var maxPixelWidth = maxWidth; var maxPixelWidth = maxWidth;
//images = images.sort(function (a, b) { return a.width - b.width });
images = images.sort((a, b) => a.width - b.width + \"\"); images = images.sort((a, b) => a.width - b.width + \"\");
return images.find(image => image.width >= maxPixelWidth) || return images.find(image => image.width >= maxPixelWidth) ||
images[images.length - 1]; images[images.length - 1];
} }"
"
`; `;

View File

@ -53,39 +53,43 @@ var obj = { f: async () => await 1 };
var objf : () => Promise<number> = obj.f; var objf : () => Promise<number> = obj.f;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// \"For async functions, a Promise<T> is returned, // \"For async functions, a Promise<T> is returned,
// and the type of return expressions must be T.\" // and the type of return expressions must be T.\"
// //
// error, number != bool
// await: (p: Promise<T> | T) => T
//
// TODO: this is one of those bad generic errors, currently:
// \"inconsistent use of library definitions\" with two core.js locs
// error, number != bool
// async arrow functions
//
// async methods
//
// error, void != Promise<void>
// async function props
async function f0(): Promise<number> { async function f0(): Promise<number> {
return 1; return 1;
} }
async function f1(): Promise<boolean> { async function f1(): Promise<boolean> {
return 1; return 1; // error, number != bool
} }
// await: (p: Promise<T> | T) => T
//
async function f2(p: Promise<number>): Promise<number> { async function f2(p: Promise<number>): Promise<number> {
var x: number = await p; var x: number = await p;
var y: number = await 1; var y: number = await 1;
return x + y; return x + y;
} }
async function f3(p: Promise<number>): Promise<number> { async function f3(p: Promise<number>): Promise<number> {
return await p; return await p;
} }
// TODO: this is one of those bad generic errors, currently:
// \"inconsistent use of library definitions\" with two core.js locs
async function f4(p: Promise<number>): Promise<boolean> { async function f4(p: Promise<number>): Promise<boolean> {
return await p; return await p; // error, number != bool
} }
// async arrow functions
//
var f5: () => Promise<number> = async () => await 1; var f5: () => Promise<number> = async () => await 1;
// async methods
//
class C { class C {
async m() { async m() {
return 1; return 1;
@ -96,13 +100,15 @@ class C {
static async m(a): void { static async m(a): void {
await a; await a;
} }
// error, void != Promise<void>
static async mt<T>(a: T): Promise<T> { static async mt<T>(a: T): Promise<T> {
return a; return a;
} }
} }
// async function props
var obj = { f: async () => await 1 }; var obj = { f: async () => await 1 };
var objf: () => Promise<number> = obj.f; var objf: () => Promise<number> = obj.f;"
"
`; `;
exports[`test async_base_class.js 1`] = ` exports[`test async_base_class.js 1`] = `
@ -126,14 +132,15 @@ async function foo() {
// am not clear on whether it should. In any case it\'s a strange corner case // am not clear on whether it should. In any case it\'s a strange corner case
// that is probably not important to support. // that is probably not important to support.
class C {} class C {}
var P: Promise<Class<C>> = new Promise(function(resolve, reject) { var P: Promise<Class<C>> = new Promise(function(resolve, reject) {
resolve(C); resolve(C);
}); });
async function foo() { async function foo() {
class Bar extends (await P) {} class Bar extends (await P) {}
return Bar; return Bar;
} }"
"
`; `;
exports[`test async_parse.js 1`] = ` exports[`test async_parse.js 1`] = `
@ -164,23 +171,28 @@ var y = { async };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
async function f() {} async function f() {}
async function ft<T>(a: T) {} async function ft<T>(a: T) {}
class C { class C {
async m() {} async m() {}
async mt<T>(a: T) {} async mt<T>(a: T) {}
static async m(a) {} static async m(a) {}
static async mt<T>(a: T) {} static async mt<T>(a: T) {}
} }
var e = async function() {}; var e = async function() {};
var et = async function<T>(a: T) {}; var et = async function<T>(a: T) {};
var n = new async function() {}(); var n = new async function() {}();
var o = { async m() {} }; var o = { async m() {} };
var ot = { async m<T>(a: T) {} }; var ot = { async m<T>(a: T) {} };
var oz = { async async() {} }; var oz = { async async() {} };
var x = { async: 5 }; var x = { async: 5 };
console.log(x.async); console.log(x.async);
var async = 3; var async = 3;
var y = { async }; var y = { async };"
"
`; `;
exports[`test async_promise.js 1`] = ` exports[`test async_promise.js 1`] = `
@ -190,8 +202,7 @@ exports[`test async_promise.js 1`] = `
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
async function f(): Promise<number> { async function f(): Promise<number> {
return Promise.resolve(1); return Promise.resolve(1);
} }"
"
`; `;
exports[`test async_return_void.js 1`] = ` exports[`test async_return_void.js 1`] = `
@ -211,17 +222,19 @@ async function foo3(): Promise<string> {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
async function foo1(): Promise<string> { async function foo1(): Promise<string> {
return; return;
} }
async function foo2(): Promise<string> { async function foo2(): Promise<string> {
return undefined; return undefined;
} }
async function foo3(): Promise<string> { async function foo3(): Promise<string> {
function bar() {} function bar() {}
return bar(); return bar();
} }"
"
`; `;
exports[`test async2.js 1`] = ` exports[`test async2.js 1`] = `
@ -287,59 +300,64 @@ function test5() {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// misc basic // misc basic
// valid
// Error: number ~> string function test1() {
async function foo() {
return 42;
}
async function bar() {
var a = await foo();
var b: number = a;
// valid
var c: string = a; // Error: number ~> string
}
}
// //
// void returns: // void returns:
// //
// inference should produce return type Promise<void> // inference should produce return type Promise<void>
// in the absence of an explicit return // in the absence of an explicit return
// //
// ok
// error, void != Promise<void>
// annotated return type of Promise<void> should work
//
// ok
// other annotated return types should fail
// (note: misannotated return types with explicit
// return statements are covered in async.js)
//
// error, void != Promise<void>
// error, number != void
function test1() {
async function foo() {
return 42;
}
async function bar() {
var a = await foo();
var b: number = a;
var c: string = a;
}
}
function test2() { function test2() {
async function voidoid1() { async function voidoid1() {
console.log(\"HEY\"); console.log(\"HEY\");
} }
var voidoid2: () => Promise<void> = voidoid1; var voidoid2: () => Promise<void> = voidoid1;
var voidoid3: () => void = voidoid1; // ok
var voidoid3: () => void = voidoid1; // error, void != Promise<void>
} }
// annotated return type of Promise<void> should work
//
function test3() { function test3() {
async function voidoid4(): Promise<void> { async function voidoid4(): Promise<void> {
// ok
console.log(\"HEY\"); console.log(\"HEY\");
} }
} }
// other annotated return types should fail
// (note: misannotated return types with explicit
// return statements are covered in async.js)
//
function test4() { function test4() {
async function voidoid5(): void { async function voidoid5(): void {
// error, void != Promise<void>
console.log(\"HEY\"); console.log(\"HEY\");
} }
} }
function test5() { function test5() {
async function voidoid6(): Promise<number> { async function voidoid6(): Promise<number> {
// error, number != void
console.log(\"HEY\"); console.log(\"HEY\");
} }
} }"
"
`; `;
exports[`test async3.js 1`] = ` exports[`test async3.js 1`] = `
@ -377,6 +395,7 @@ async function baz() {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
/** /**
* test nested-promise unwrapping. * test nested-promise unwrapping.
* Note: currently we don\'t do this properly in the underlying * Note: currently we don\'t do this properly in the underlying
@ -384,24 +403,28 @@ async function baz() {
* be raised here. Once that\'s fixed, the errors here will go * be raised here. Once that\'s fixed, the errors here will go
* away. * away.
*/ */
// a should now be typed as number, but is in fact
// Promise<number> until nested-promise unwrap is fixed
// TODO this is valid code, but currently gives Promise ~> number error
// due to lack of transitive Promise unwrap.
// should be number ~> string error, but currently gives
// Promise ~> string error for the same reason
async function foo() { async function foo() {
return 42; return 42;
} }
async function bar() { async function bar() {
return foo(); return foo();
} }
async function baz() { async function baz() {
// a should now be typed as number, but is in fact
// Promise<number> until nested-promise unwrap is fixed
var a = await bar(); var a = await bar();
// TODO this is valid code, but currently gives Promise ~> number error
// due to lack of transitive Promise unwrap.
var b: number = a; var b: number = a;
// should be number ~> string error, but currently gives
// Promise ~> string error for the same reason
var c: string = a; var c: string = a;
} }"
"
`; `;
exports[`test await_parse.js 1`] = ` exports[`test await_parse.js 1`] = `
@ -436,6 +459,7 @@ async function f() {
async function ft<T>(a: T) { async function ft<T>(a: T) {
await 1; await 1;
} }
class C { class C {
async m() { async m() {
await 1; await 1;
@ -450,15 +474,18 @@ class C {
await 1; await 1;
} }
} }
var e = async function() { var e = async function() {
await 1; await 1;
}; };
var et = async function<T>(a: T) { var et = async function<T>(a: T) {
await 1; await 1;
}; };
var n = new async function() { var n = new async function() {
await 1; await 1;
}(); }();
var o = { var o = {
async m() { async m() {
await 1; await 1;
@ -474,9 +501,10 @@ var oz = {
await async; await async;
} }
}; };
var x = { await: 5 }; var x = { await: 5 };
console.log(x.await); console.log(x.await);
var await = 3; var await = 3;
var y = { await }; var y = { await };"
"
`; `;

View File

@ -26,16 +26,14 @@ async function *delegate_return() {
var x: void = yield *inner(); // error: number ~> void var x: void = yield *inner(); // error: number ~> void
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: number ~> void
// error: number ~> void
// error: number ~> void
async function* delegate_next() { async function* delegate_next() {
async function* inner() { async function* inner() {
var x: void = yield; var x: void = yield; // error: number ~> void
} }
yield* inner(); yield* inner();
} }
delegate_next().next(0); delegate_next().next(0);
async function* delegate_yield() { async function* delegate_yield() {
async function* inner() { async function* inner() {
yield 0; yield 0;
@ -44,16 +42,16 @@ async function* delegate_yield() {
} }
async () => { async () => {
for await (const x of delegate_yield()) { for await (const x of delegate_yield()) {
(x: void); (x: void); // error: number ~> void
} }
}; };
async function* delegate_return() { async function* delegate_return() {
async function* inner() { async function* inner() {
return 0; return 0;
} }
var x: void = yield* inner(); var x: void = yield* inner(); // error: number ~> void
} }"
"
`; `;
exports[`test generator.js 1`] = ` exports[`test generator.js 1`] = `
@ -83,11 +81,13 @@ async function f() {
} }
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: string ~> void
interface File { readLine(): Promise<string>, close(): void, EOF: boolean } interface File { readLine(): Promise<string>, close(): void, EOF: boolean }
declare function fileOpen(path: string): Promise<File>; declare function fileOpen(path: string): Promise<File>;
async function* readLines(path) { async function* readLines(path) {
let file: File = await fileOpen(path); let file: File = await fileOpen(path);
try { try {
while (!file.EOF) { while (!file.EOF) {
yield await file.readLine(); yield await file.readLine();
@ -96,12 +96,12 @@ async function* readLines(path) {
file.close(); file.close();
} }
} }
async function f() { async function f() {
for await (const line of readLines(\"/path/to/file\")) { for await (const line of readLines(\"/path/to/file\")) {
(line: void); (line: void); // error: string ~> void
} }
} }"
"
`; `;
exports[`test return.js 1`] = ` exports[`test return.js 1`] = `
@ -128,16 +128,16 @@ refuse_return().return(\"string\").then(result => {
} }
}); });
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
declare var gen: AsyncGenerator<void, string, void>;
// You can pass whatever you like to return, it doesn\'t need to be related to // You can pass whatever you like to return, it doesn\'t need to be related to
// the AsyncGenerator\'s return type // the AsyncGenerator\'s return type
// error: string | number ~> void gen.return(0).then(result => {
(result.value: void); // error: string | number ~> void
});
// However, a generator can \"refuse\" the return by catching an exception and // However, a generator can \"refuse\" the return by catching an exception and
// yielding or returning internally. // yielding or returning internally.
// error: number | void ~> string
declare var gen: AsyncGenerator<void, string, void>;
gen.return(0).then(result => {
(result.value: void);
});
async function* refuse_return() { async function* refuse_return() {
try { try {
yield 1; yield 1;
@ -147,10 +147,9 @@ async function* refuse_return() {
} }
refuse_return().return(\"string\").then(result => { refuse_return().return(\"string\").then(result => {
if (result.done) { if (result.done) {
(result.value: string); (result.value: string); // error: number | void ~> string
} }
}); });"
"
`; `;
exports[`test throw.js 1`] = ` exports[`test throw.js 1`] = `
@ -187,8 +186,6 @@ async function *yield_return() {
}); });
}); });
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: number ~> void
// error: number ~> void
async function* catch_return() { async function* catch_return() {
try { try {
yield 0; yield 0;
@ -196,13 +193,15 @@ async function* catch_return() {
return e; return e;
} }
} }
async () => { async () => {
catch_return().throw(\"\").then(({ value }) => { catch_return().throw(\"\").then(({ value }) => {
if (value !== undefined) { if (value !== undefined) {
(value: void); (value: void); // error: number ~> void
} }
}); });
}; };
async function* yield_return() { async function* yield_return() {
try { try {
yield 0; yield 0;
@ -211,12 +210,12 @@ async function* yield_return() {
yield e; yield e;
} }
} }
async () => { async () => {
yield_return().throw(\"\").then(({ value }) => { yield_return().throw(\"\").then(({ value }) => {
if (value !== undefined) { if (value !== undefined) {
(value: void); (value: void); // error: number ~> void
} }
}); });
}; };"
"
`; `;

View File

@ -12,6 +12,7 @@ declare var objectAssign: Object$Assign
m m
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
declare var idx: $Facebookism$Idx; declare var idx: $Facebookism$Idx;
declare var merge: $Facebookism$Merge; declare var merge: $Facebookism$Merge;
declare var mergeDeepInto: $Facebookism$MergeDeepInto; declare var mergeDeepInto: $Facebookism$MergeDeepInto;
@ -19,8 +20,8 @@ declare var mergeInto: $Facebookism$MergeInto;
declare var mixin: $Facebookism$Mixin; declare var mixin: $Facebookism$Mixin;
declare var objectGetPrototypeOf: Object$GetPrototypeOf; declare var objectGetPrototypeOf: Object$GetPrototypeOf;
declare var objectAssign: Object$Assign; declare var objectAssign: Object$Assign;
m;
" m;"
`; `;
exports[`test unknown.js 1`] = ` exports[`test unknown.js 1`] = `
@ -28,6 +29,5 @@ exports[`test unknown.js 1`] = `
module.exports = { x: { y: \"\" } }; module.exports = { x: { y: \"\" } };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @noflow // @noflow
module.exports = { x: { y: \"\" } }; module.exports = { x: { y: \"\" } };"
"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test client.js 1`] = ` exports[`test client.js 1`] = `
"var y:number = x; "var y:number = x;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var y: number = x; var y: number = x;"
"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test lib.js 1`] = ` exports[`test lib.js 1`] = `
"declare var x: string; "declare var x: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
declare var x: string; declare var x: string;"
"
`; `;

View File

@ -55,64 +55,61 @@ let tests = [
] ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// objects on RHS
// arrays on RHS
// primitive classes on RHS
// primitives on RHS
// error
// error
// error
// error
// bogus stuff on LHS
// error
// error
// error
// error
// error
// in predicates
// error
// error, !\'foo\' is a boolean
// annotations on RHS
// ok
// error
let tests = [ let tests = [
// objects on RHS
function() { function() {
\"foo\" in {}; \"foo\" in {};
\"foo\" in { foo: null }; \"foo\" in { foo: null };
0 in {}; 0 in {};
0 in { \"0\": null }; 0 in { \"0\": null };
}, },
// arrays on RHS
function() { function() {
\"foo\" in []; \"foo\" in [];
0 in []; 0 in [];
\"length\" in []; \"length\" in [];
}, },
// primitive classes on RHS
function() { function() {
\"foo\" in new String(\"bar\"); \"foo\" in new String(\"bar\");
\"foo\" in new Number(123); \"foo\" in new Number(123);
}, },
// primitives on RHS
function() { function() {
\"foo\" in 123; \"foo\" in 123;
// error
\"foo\" in \"bar\"; \"foo\" in \"bar\";
// error
\"foo\" in void 0; \"foo\" in void 0;
\"foo\" in null; // error
\"foo\" in null; // error
}, },
// bogus stuff on LHS
function() { function() {
null in {}; null in {};
// error
void 0 in {}; void 0 in {};
// error
({}) in {}; ({}) in {};
// error
[] in {}; [] in {};
false in []; // error
false in []; // error
}, },
// in predicates
function() { function() {
if (\"foo\" in 123) {} if (\"foo\" in 123) {}
// error
if (!\"foo\" in {}) {} if (!\"foo\" in {}) {}
// error, !\'foo\' is a boolean
if (!(\"foo\" in {})) {} if (!(\"foo\" in {})) {}
}, },
// annotations on RHS
function(x: Object, y: mixed) { function(x: Object, y: mixed) {
\"foo\" in x; \"foo\" in x;
\"foo\" in y; // ok
\"foo\" in y; // error
} }
]; ];"
"
`; `;

View File

@ -27,12 +27,9 @@ for (const { baz } of bazzes) {
(baz: number); // error: string ~> number (baz: number); // error: string ~> number
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// errors: const cannot be reassigned
// regression tests -- OK to assign consts like this:
// error: string ~> number
// error: string ~> number
// error: string ~> number
const x = 0; const x = 0;
// errors: const cannot be reassigned
x++; x++;
x--; x--;
x += 0; x += 0;
@ -45,15 +42,18 @@ x >>>= 0;
x |= 0; x |= 0;
x ^= 0; x ^= 0;
x &= 0; x &= 0;
// regression tests -- OK to assign consts like this:
const { foo } = { foo: \"foo\" }; const { foo } = { foo: \"foo\" };
const [ bar ] = [ \"bar\" ]; const [ bar ] = [ \"bar\" ];
(foo: number); (foo: number);
// error: string ~> number
(bar: number); (bar: number);
// error: string ~> number
declare var bazzes: { baz: string }[]; declare var bazzes: { baz: string }[];
for (const { baz } of bazzes) { for (const { baz } of bazzes) {
(baz: number); (baz: number); // error: string ~> number
} }"
"
`; `;
exports[`test rebinding.js 1`] = ` exports[`test rebinding.js 1`] = `
@ -265,188 +265,189 @@ function fn_params_clash_fn_binding(x,y) {
* const x x x x x x * const x x x x x x
* var x x x x * var x x x x
*/ */
// type x * // type x *
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// error: type alias ref\'d from value pos
// class x *
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// let x *
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// const x *
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// error: cannot be reassigned
// var x *
// error: name already bound
// error: name already bound
// error: name already bound
// error: name already bound
// OK
// function x *
// OK
// error: name already bound
// corner cases
// error: name already bound
// error: name already bound
// fn params name clash
/* error: x already bound */
// error: x already bound
// OK
function type_type() { function type_type() {
type A = number; type A = number;
type A = number; type A = number; // error: name already bound
} }
function type_class() { function type_class() {
type A = number; type A = number;
class A {} class A {} // error: name already bound
} }
function type_let() { function type_let() {
type A = number; type A = number;
let A = 0; let A = 0; // error: name already bound
} }
function type_const() { function type_const() {
type A = number; type A = number;
const A = 0; const A = 0; // error: name already bound
} }
function type_var() { function type_var() {
type A = number; type A = number;
var A = 0; var A = 0; // error: name already bound
} }
function type_reassign() { function type_reassign() {
type A = number; type A = number;
A = 42; A = 42; // error: type alias ref\'d from value pos
} }
// class x *
function class_type() { function class_type() {
class A {} class A {}
type A = number; type A = number; // error: name already bound
} }
function class_class() { function class_class() {
class A {} class A {}
class A {} class A {} // error: name already bound
} }
function class_let() { function class_let() {
class A {} class A {}
let A = 0; let A = 0; // error: name already bound
} }
function class_const() { function class_const() {
class A {} class A {}
const A = 0; const A = 0; // error: name already bound
} }
function class_var() { function class_var() {
class A {} class A {}
var A = 0; var A = 0; // error: name already bound
} }
// let x *
function let_type() { function let_type() {
let A = 0; let A = 0;
type A = number; type A = number; // error: name already bound
} }
function let_class() { function let_class() {
let A = 0; let A = 0;
class A {} class A {} // error: name already bound
} }
function let_let() { function let_let() {
let A = 0; let A = 0;
let A = 0; let A = 0; // error: name already bound
} }
function let_const() { function let_const() {
let A = 0; let A = 0;
const A = 0; const A = 0; // error: name already bound
} }
function let_var() { function let_var() {
let A = 0; let A = 0;
var A = 0; var A = 0; // error: name already bound
} }
// const x *
function const_type() { function const_type() {
const A = 0; const A = 0;
type A = number; type A = number; // error: name already bound
} }
function const_class() { function const_class() {
const A = 0; const A = 0;
class A {} class A {} // error: name already bound
} }
function const_let() { function const_let() {
const A = 0; const A = 0;
let A = 0; let A = 0; // error: name already bound
} }
function const_const() { function const_const() {
const A = 0; const A = 0;
const A = 0; const A = 0; // error: name already bound
} }
function const_var() { function const_var() {
const A = 0; const A = 0;
var A = 0; var A = 0; // error: name already bound
} }
function const_reassign() { function const_reassign() {
const A = 0; const A = 0;
A = 42; A = 42; // error: cannot be reassigned
} }
// var x *
function var_type() { function var_type() {
var A = 0; var A = 0;
type A = number; type A = number; // error: name already bound
} }
function var_class() { function var_class() {
var A = 0; var A = 0;
class A {} class A {} // error: name already bound
} }
function var_let() { function var_let() {
var A = 0; var A = 0;
let A = 0; let A = 0; // error: name already bound
} }
function var_const() { function var_const() {
var A = 0; var A = 0;
const A = 0; const A = 0; // error: name already bound
} }
function var_var() { function var_var() {
var A = 0; var A = 0;
var A = 0; var A = 0; // OK
} }
// function x *
function function_toplevel() { function function_toplevel() {
function a() {} function a() {}
function a() {} function a() {}
} }
function function_block() { function function_block() {
{ {
function a() {} function a() {}
function a() {} function a() {}
} }
} }
// corner cases
function var_shadow_nested_scope() { function var_shadow_nested_scope() {
{ {
let x = 0; let x = 0;
{ {
var x = 0; var x = 0; // error: name already bound
} }
} }
} }
function type_shadow_nested_scope() { function type_shadow_nested_scope() {
{ {
let x = 0; let x = 0;
{ {
type x = string; type x = string; // error: name already bound
} }
} }
} }
function fn_params_name_clash(x, x) {}
// fn params name clash
function fn_params_name_clash(x, x /* error: x already bound */) {}
function fn_params_clash_fn_binding(x, y) { function fn_params_clash_fn_binding(x, y) {
let x = 0; let x = 0;
var y = 0; // error: x already bound
} var y = 0; // OK
" }"
`; `;
exports[`test scope.js 1`] = ` exports[`test scope.js 1`] = `
@ -560,125 +561,124 @@ function default_param_2() {
} }
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ok: local to block
// error: string ~> number
// ok: local to switch
// error: string ~> number
// error: a already bound in switch
// a switch is a single lexical scope, so lets and non-disjoint
// cases can mix in odd ways. our support for edge cases is not
// yet perfect.
// error: assign before declaration
// error: use before declaration
// error: skipped initializer
// error: skipped initializer
// error: a no longer in scope
// ok
// ok
// ok
/* ok: local to init */
/* error: string ~> number */
/* ok: local to init */
/* error: string ~> number */
/* ok: local to init */
/* error: string ~> number */
// function binding in scope in default expr
// error: number ~> string
// fn body bindings not visible from param scope
// error: string ~> number
/* error: cannot resolve b */
function block_scope() { function block_scope() {
let a: number = 0; let a: number = 0;
var b: number = 0; var b: number = 0;
{ {
let a = \"\"; let a = \"\";
var b = \"\"; // ok: local to block
var b = \"\"; // error: string ~> number
} }
} }
function switch_scope(x: string) { function switch_scope(x: string) {
let a: number = 0; let a: number = 0;
var b: number = 0; var b: number = 0;
switch (x) { switch (x) {
case \"foo\": case \"foo\":
let a = \"\"; let a = \"\";
// ok: local to switch
var b = \"\"; var b = \"\";
// error: string ~> number
break; break;
case \"bar\": case \"bar\":
let a = \"\"; let a = \"\";
// error: a already bound in switch
break; break;
} }
} }
// a switch is a single lexical scope, so lets and non-disjoint
// cases can mix in odd ways. our support for edge cases is not
// yet perfect.
function switch_scope2(x: number) { function switch_scope2(x: number) {
switch (x) { switch (x) {
case 0: case 0:
a = \"\"; a = \"\";
// error: assign before declaration
break; break;
case 1: case 1:
var b = a; var b = a;
// error: use before declaration
break; break;
case 2: case 2:
let a = \"\"; let a = \"\";
break; break;
case 3: case 3:
a = \"\"; a = \"\";
// error: skipped initializer
break; break;
case 4: case 4:
var c: string = a; var c: string = a;
// error: skipped initializer
break; break;
} }
a = \"\"; a = \"\"; // error: a no longer in scope
} }
function try_scope() { function try_scope() {
let a: number = 0; let a: number = 0;
try { try {
let a = \"\"; let a = \"\"; // ok
} catch (e) { } catch (e) {
let a = \"\"; let a = \"\"; // ok
} finally { } finally {
let a = \"\"; let a = \"\"; // ok
} }
} }
function for_scope_let() { function for_scope_let() {
let a: number = 0; let a: number = 0;
for (let a = \"\"; ; ) {} for (let a = \"\" /* ok: local to init */; ; ) {}
} }
function for_scope_var() { function for_scope_var() {
var a: number = 0; var a: number = 0;
for (var a = \"\"; ; ) {} for (var a = \"\" /* error: string ~> number */; ; ) {}
} }
function for_in_scope_let(o: Object) { function for_in_scope_let(o: Object) {
let a: number = 0; let a: number = 0;
for (let a in o) {} for (let a /* ok: local to init */ in o) {}
} }
function for_in_scope_var(o: Object) { function for_in_scope_var(o: Object) {
var a: number = 0; var a: number = 0;
for (var a in o) {} for (var a /* error: string ~> number */ in o) {}
} }
function for_of_scope_let(xs: string[]) { function for_of_scope_let(xs: string[]) {
let a: number = 0; let a: number = 0;
for (let a of xs) {} for (let a /* ok: local to init */ of xs) {}
} }
function for_of_scope_var(xs: string[]) { function for_of_scope_var(xs: string[]) {
var a: number = 0; var a: number = 0;
for (var a of xs) {} for (var a /* error: string ~> number */ of xs) {}
} }
function default_param_1() { function default_param_1() {
function f(x: () => string = f): number { // function binding in scope in default expr
function f(
// error: number ~> string
x: () => string = f
): number {
return 0; return 0;
} }
} }
function default_param_2() { function default_param_2() {
// fn body bindings not visible from param scope
let a = \"\"; let a = \"\";
function f0(x = () => a): number { function f0(x = () => a): number {
let a = 0; let a = 0;
return x(); return x(); // error: string ~> number
} }
function f1(x = b): number { function f1(x = b /* error: cannot resolve b */): number {
let b = 0; let b = 0;
return x; return x;
} }
} }"
"
`; `;
exports[`test tdz.js 1`] = ` exports[`test tdz.js 1`] = `
@ -784,9 +784,15 @@ a = 10;
f(a); // ok, a: number (not ?number) f(a); // ok, a: number (not ?number)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** @flow */ /** @flow */
// -- types --- // -- types ---
// type aliases are hoisted and always available // type aliases are hoisted and always available
type T1 = T2;
// ok // ok
type T2 = number;
// --- lets --- // --- lets ---
// to be correct, we would // to be correct, we would
// - not allow forward refs to lets from value positions, // - not allow forward refs to lets from value positions,
@ -799,92 +805,96 @@ f(a); // ok, a: number (not ?number)
// a lambda runs. But a simple conservative approach would prohibit // a lambda runs. But a simple conservative approach would prohibit
// forward references to let/consts from within lambdas entirely, // forward references to let/consts from within lambdas entirely,
// which would be annoying. TODO // which would be annoying. TODO
// errors, let + const referenced before decl
// error, attempt to write to let before decl
// error, attempt to write to let before decl
// errors, let + const referenced before decl
// functions are let-scoped and hoisted
// ok, finds hoisted outer
// ok, finds hoisted inner
// ok, hoisted outer not clobbered
// out-of-scope TDZ not enforced. sometimes right...
// ok, g doesn\'t run in TDZ
// ...sometimes wrong
// should error, but doesn\'t currently
// - from type positions, we currently error on forward refs to any
// value (i.e., class or function). this is a basic flaw in our
// phasing of AST traversal, and will be fixed.
//
// ok
// error: let ref before decl from value position
// ok
// --- vars ---
// it\'s possible to annotate a var with a non-maybe type,
// but leave it uninitialized until later (as long as it\'s
// initialized before use)
// not an error per se - only if used before init
// error: undefined ~/> number
// ok, a: number (not ?number)
type T1 = T2;
type T2 = number;
function f0() { function f0() {
var v = x * c; var v = x * c;
// errors, let + const referenced before decl
let x = 0; let x = 0;
const c = 0; const c = 0;
} }
function f1(b) { function f1(b) {
x = 10; x = 10;
// error, attempt to write to let before decl
let x = 0; let x = 0;
if (b) { if (b) {
y = 10; y = 10;
// error, attempt to write to let before decl
let y = 0; let y = 0;
} }
} }
function f2() { function f2() {
{ {
var v = x * c; var v = x * c; // errors, let + const referenced before decl
} }
let x = 0; let x = 0;
const c = 0; const c = 0;
} }
// functions are let-scoped and hoisted
function f3() { function f3() {
var s: string = foo(); var s: string = foo();
// ok, finds hoisted outer
{ {
var n: number = foo(); var n: number = foo();
// ok, finds hoisted inner
function foo() { function foo() {
return 0; return 0;
} }
} }
var s2: string = foo(); var s2: string = foo();
// ok, hoisted outer not clobbered
function foo() { function foo() {
return \"\"; return \"\";
} }
} }
// out-of-scope TDZ not enforced. sometimes right...
function f4() { function f4() {
function g() { function g() {
return x + c; return x + c;
} }
// ok, g doesn\'t run in TDZ
let x = 0; let x = 0;
const c = 0; const c = 0;
} }
// ...sometimes wrong
function f5() { function f5() {
function g() { function g() {
return x; return x;
} }
g(); g();
// should error, but doesn\'t currently
let x = 0; let x = 0;
const c = 0; const c = 0;
} }
// - from type positions, we currently error on forward refs to any
// value (i.e., class or function). this is a basic flaw in our
// phasing of AST traversal, and will be fixed.
//
var x: C; var x: C;
// ok
var y = new C(); var y = new C();
// error: let ref before decl from value position
class C {} class C {}
var z: C = new C(); var z: C = new C();
// ok
// --- vars ---
// it\'s possible to annotate a var with a non-maybe type,
// but leave it uninitialized until later (as long as it\'s
// initialized before use)
var a: number; var a: number;
// not an error per se - only if used before init
function f(n: number) { function f(n: number) {
return n; return n;
} }
f(a); f(a);
// error: undefined ~/> number
a = 10; a = 10;
f(a);
" f(a); // ok, a: number (not ?number)"
`; `;

View File

@ -68,109 +68,108 @@ for (let [x, y]: [string, number] of a.entries()) {} // incorrect
for (let [x, y]: [number, number] of a.entries()) {} // incorrect for (let [x, y]: [number, number] of a.entries()) {} // incorrect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// constructor // constructor
const a: FormData = new FormData();
// correct // correct
new FormData(\"\");
// incorrect // incorrect
new FormData(document.createElement(\"input\"));
// incorrect // incorrect
new FormData(document.createElement(\"form\"));
// correct // correct
// has // has
const b: boolean = a.has(\"foo\");
// correct // correct
// get // get
const c: ?(string | File) = a.get(\"foo\");
// correct // correct
const d: string = a.get(\"foo\");
// incorrect // incorrect
const e: Blob = a.get(\"foo\");
// incorrect // incorrect
const f: ?(string | File | Blob) = a.get(\"foo\");
// incorrect // incorrect
a.get(2);
// incorrect // incorrect
// getAll // getAll
const a1: Array<string | File> = a.getAll(\"foo\");
// correct // correct
const a2: Array<string | File | number> = a.getAll(\"foo\");
// incorrect // incorrect
const a3: Array<string | Blob | File> = a.getAll(\"foo\");
// incorrect // incorrect
a.getAll(23);
// incorrect // incorrect
// set // set
a.set(\"foo\", \"bar\");
// correct // correct
a.set(\"foo\", {});
// incorrect // incorrect
a.set(2, \"bar\");
// incorrect // incorrect
a.set(\"foo\", \"bar\", \"baz\");
// incorrect // incorrect
a.set(\"bar\", new File([], \"q\"));
// correct // correct
a.set(\"bar\", new File([], \"q\"), \"x\");
// correct // correct
a.set(\"bar\", new File([], \"q\"), 2);
// incorrect // incorrect
a.set(\"bar\", new Blob());
// correct // correct
a.set(\"bar\", new Blob(), \"x\");
// correct // correct
a.set(\"bar\", new Blob(), 2);
// incorrect // incorrect
// append // append
a.append(\"foo\", \"bar\");
// correct // correct
a.append(\"foo\", {});
// incorrect // incorrect
a.append(2, \"bar\");
// incorrect // incorrect
a.append(\"foo\", \"bar\", \"baz\");
// incorrect // incorrect
a.append(\"foo\", \"bar\");
// incorrect // incorrect
a.append(\"bar\", new File([], \"q\"));
// correct // correct
a.append(\"bar\", new File([], \"q\"), \"x\");
// correct // correct
a.append(\"bar\", new File([], \"q\"), 2);
// incorrect // incorrect
a.append(\"bar\", new Blob());
// correct // correct
a.append(\"bar\", new Blob(), \"x\");
// correct // correct
a.append(\"bar\", new Blob(), 2);
// incorrect // incorrect
// delete // delete
a.delete(\"xx\");
// correct // correct
a.delete(3);
// incorrect // incorrect
// keys // keys
for (let x: string of a.keys()) {}
// correct // correct
for (let x: number of a.keys()) {}
// incorrect // incorrect
// values // values
for (let x: string | File of a.values()) {}
// correct // correct
for (let x: string | File | Blob of a.values()) {}
// incorrect // incorrect
// entries // entries
// correct
// incorrect
// incorrect
// incorrect
// incorrect
const a: FormData = new FormData();
new FormData(\"\");
new FormData(document.createElement(\"input\"));
new FormData(document.createElement(\"form\"));
const b: boolean = a.has(\"foo\");
const c: ?(string | File) = a.get(\"foo\");
const d: string = a.get(\"foo\");
const e: Blob = a.get(\"foo\");
const f: ?(string | File | Blob) = a.get(\"foo\");
a.get(2);
const a1: Array<string | File> = a.getAll(\"foo\");
const a2: Array<string | File | number> = a.getAll(\"foo\");
const a3: Array<string | Blob | File> = a.getAll(\"foo\");
a.getAll(23);
a.set(\"foo\", \"bar\");
a.set(\"foo\", {});
a.set(2, \"bar\");
a.set(\"foo\", \"bar\", \"baz\");
a.set(\"bar\", new File([], \"q\"));
a.set(\"bar\", new File([], \"q\"), \"x\");
a.set(\"bar\", new File([], \"q\"), 2);
a.set(\"bar\", new Blob());
a.set(\"bar\", new Blob(), \"x\");
a.set(\"bar\", new Blob(), 2);
a.append(\"foo\", \"bar\");
a.append(\"foo\", {});
a.append(2, \"bar\");
a.append(\"foo\", \"bar\", \"baz\");
a.append(\"foo\", \"bar\");
a.append(\"bar\", new File([], \"q\"));
a.append(\"bar\", new File([], \"q\"), \"x\");
a.append(\"bar\", new File([], \"q\"), 2);
a.append(\"bar\", new Blob());
a.append(\"bar\", new Blob(), \"x\");
a.append(\"bar\", new Blob(), 2);
a.delete(\"xx\");
a.delete(3);
for (let x: string of a.keys()) {}
for (let x: number of a.keys()) {}
for (let x: string | File of a.values()) {}
for (let x: string | File | Blob of a.values()) {}
for (let [ x, y ]: [string, string | File] of a.entries()) {} for (let [ x, y ]: [string, string | File] of a.entries()) {}
// correct
for (let [ x, y ]: [string, string | File | Blob] of a.entries()) {} for (let [ x, y ]: [string, string | File | Blob] of a.entries()) {}
// incorrect
for (let [ x, y ]: [number, string] of a.entries()) {} for (let [ x, y ]: [number, string] of a.entries()) {}
// incorrect
for (let [ x, y ]: [string, number] of a.entries()) {} for (let [ x, y ]: [string, number] of a.entries()) {}
for (let [ x, y ]: [number, number] of a.entries()) {} // incorrect
" for (let [ x, y ]: [number, number] of a.entries()) {} // incorrect"
`; `;
exports[`test MutationObserver.js 1`] = ` exports[`test MutationObserver.js 1`] = `
@ -205,26 +204,8 @@ o.takeRecords(); // correct
o.disconnect(); // correct o.disconnect(); // correct
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// constructor // constructor
// correct
// correct
// correct
// incorrect
// incorrect
// incorrect
// observe
// correct
// correct
// incorrect
// incorrect
// incorrect
// incorrect
// incorrect
// incorrect
// takeRecords
// correct
// disconnect
// correct
function callback( function callback(
arr: Array<MutationRecord>, arr: Array<MutationRecord>,
observer: MutationObserver observer: MutationObserver
@ -232,21 +213,38 @@ function callback(
return; return;
} }
const o: MutationObserver = new MutationObserver(callback); const o: MutationObserver = new MutationObserver(callback);
// correct
new MutationObserver((arr: Array<MutationRecord>) => true); new MutationObserver((arr: Array<MutationRecord>) => true);
// correct
new MutationObserver(() => {}); new MutationObserver(() => {});
// correct
new MutationObserver(); new MutationObserver();
// incorrect
new MutationObserver(42); new MutationObserver(42);
// incorrect
new MutationObserver((n: number) => {}); new MutationObserver((n: number) => {});
// incorrect
// observe
const div = document.createElement(\"div\"); const div = document.createElement(\"div\");
o.observe(div, { attributes: true, attributeFilter: [ \"style\" ] }); o.observe(div, { attributes: true, attributeFilter: [ \"style\" ] });
// correct
o.observe(div, { characterData: true, invalid: true }); o.observe(div, { characterData: true, invalid: true });
// correct
o.observe(); o.observe();
// incorrect
o.observe(\"invalid\"); o.observe(\"invalid\");
// incorrect
o.observe(div); o.observe(div);
// incorrect
o.observe(div, {}); o.observe(div, {});
// incorrect
o.observe(div, { subtree: true }); o.observe(div, { subtree: true });
// incorrect
o.observe(div, { attributes: true, attributeFilter: true }); o.observe(div, { attributes: true, attributeFilter: true });
// incorrect
// takeRecords
o.takeRecords(); o.takeRecords();
o.disconnect(); // correct
" // disconnect
o.disconnect(); // correct"
`; `;

View File

@ -6,10 +6,10 @@ function bar<X:number, Y:X>(x:X, y:Y): number { return y*0; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function foo<X, Y: X>(x: X, y: Y): void {} function foo<X, Y: X>(x: X, y: Y): void {}
foo(0, \"\"); foo(0, \"\");
function bar<X: number, Y: X>(x: X, y: Y): number { function bar<X: number, Y: X>(x: X, y: Y): number {
return y * 0; return y * 0;
} }"
"
`; `;
exports[`test test.js 1`] = ` exports[`test test.js 1`] = `
@ -39,38 +39,37 @@ var q: number = c.qux(0);
/* 2 more errors, since argument U = number is incompatible with T = string, and /* 2 more errors, since argument U = number is incompatible with T = string, and
* result T = string is incompatible with number */ * result T = string is incompatible with number */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// OK
// error
// OK
// error, since T: number and U: number does not imply U: T
// OK, since T: number and U: T implies U: number
// error
// OK, since U: T
// error, since T = string is incompatible with number
/* 2 more errors, since argument U = number is incompatible with T = string, and
* result T = string is incompatible with number */
function foo<T: number>(x: T): T { function foo<T: number>(x: T): T {
var _ = x * 1; var _ = x * 1;
// OK
var y: string = x; var y: string = x;
return x; // error
return x; // OK
} }
class C<T: number> { class C<T: number> {
bar<U: number>(x: U): T { bar<U: number>(x: U): T {
return x; return x; // error, since T: number and U: number does not imply U: T
} }
qux<U: T>(x: U): T { qux<U: T>(x: U): T {
var _ = x * 1; var _ = x * 1;
// OK, since T: number and U: T implies U: number
var y: string = x; var y: string = x;
return x; // error
return x; // OK, since U: T
} }
} }
function example<T: { x: number }>(o: T): T { function example<T: { x: number }>(o: T): T {
o.x = 0; o.x = 0;
return o; return o;
} }
var obj1: { x: number, y: string } = example({ x: 0, y: \"\" }); var obj1: { x: number, y: string } = example({ x: 0, y: \"\" });
var obj2: { x: number } = example({ x: 0 }); var obj2: { x: number } = example({ x: 0 });
var c: C<string> = new C(); var c: C<string> = new C();
// error, since T = string is incompatible with number
var q: number = c.qux(0); var q: number = c.qux(0);
" /* 2 more errors, since argument U = number is incompatible with T = string, and
* result T = string is incompatible with number */"
`; `;

View File

@ -68,19 +68,6 @@ function test_const() {
return st; return st;
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: boolean !~> number
// 2 errors: ?string !~> number
// error: boolean !~> number
// 2 errors: (boolean | string) !~> number
// 2 errors: (boolean | string) !~> number
// error: boolean !~> number
// 2 errors: (boolean | string) !~> number
// 2 errors: (boolean | string) !~> number
// error: string !~> number
// error: string !~> number
// same basic test as foo(), but with const. probes the
// logic that still uses havoc to do env resets.
// no error
function foo(b) { function foo(b) {
var x = b ? null : false; var x = b ? null : false;
var z; var z;
@ -89,10 +76,11 @@ function foo(b) {
z = \"\"; z = \"\";
break; break;
} }
var y: number = x; var y: number = x; // error: boolean !~> number
} }
var w: number = z; var w: number = z; // 2 errors: ?string !~> number
} }
function bar(b) { function bar(b) {
var x = b ? null : false; var x = b ? null : false;
if (x == null) if (x == null)
@ -100,14 +88,17 @@ function bar(b) {
switch (\"\") { switch (\"\") {
case 0: case 0:
var y: number = x; var y: number = x;
// error: boolean !~> number
x = \"\"; x = \"\";
case 1: case 1:
var z: number = x; var z: number = x;
// 2 errors: (boolean | string) !~> number
break; break;
case 2: case 2:
} }
var w: number = x; var w: number = x; // 2 errors: (boolean | string) !~> number
} }
function bar2(b) { function bar2(b) {
var x = b ? null : false; var x = b ? null : false;
if (x == null) if (x == null)
@ -115,16 +106,19 @@ function bar2(b) {
switch (\"\") { switch (\"\") {
case 0: { case 0: {
let y: number = x; let y: number = x;
// error: boolean !~> number
x = \"\"; x = \"\";
} }
case 1: { case 1: {
let z: number = x; let z: number = x;
// 2 errors: (boolean | string) !~> number
break; break;
} }
case 2: case 2:
} }
var w: number = x; var w: number = x; // 2 errors: (boolean | string) !~> number
} }
function qux(b) { function qux(b) {
var z = 0; var z = 0;
while (b) { while (b) {
@ -133,20 +127,26 @@ function qux(b) {
z = \"\"; z = \"\";
continue; continue;
} }
// error: string !~> number
z = 0; z = 0;
} }
var w: number = z; var w: number = z; // error: string !~> number
} }
// same basic test as foo(), but with const. probes the
// logic that still uses havoc to do env resets.
function test_const() { function test_const() {
let st: string = \"abc\"; let st: string = \"abc\";
for (let i = 1; i < 100; i++) { for (let i = 1; i < 100; i++) {
const fooRes: ?string = \"HEY\"; const fooRes: ?string = \"HEY\";
if (!fooRes) { if (!fooRes) {
break; break;
} }
st = fooRes;
st = fooRes; // no error
} }
return st; return st;
} }"
"
`; `;

View File

@ -5,8 +5,7 @@ module.exports = o;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var o = Object.freeze({ foo: 0 }); var o = Object.freeze({ foo: 0 });
(o.foo: string); (o.foo: string);
module.exports = o; module.exports = o;"
"
`; `;
exports[`test test2.js 1`] = ` exports[`test test2.js 1`] = `
@ -14,6 +13,5 @@ exports[`test test2.js 1`] = `
(o.foo: string); (o.foo: string);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var o = require(\"./test\"); var o = require(\"./test\");
(o.foo: string); (o.foo: string);"
"
`; `;

View File

@ -17,21 +17,20 @@ function g() {
foo = foo1; foo = foo1;
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: number !~> string
// error: string !~> number
// error: string !~> number
var a = [ \"...\" ]; var a = [ \"...\" ];
var b = a.map(function(x) { var b = a.map(function(x) {
return 0; return 0;
}); });
var c: string = b[0]; var c: string = b[0];
// error: number !~> string
var array = []; var array = [];
function f() { function f() {
array = array.map(function() { array = array.map(function() {
return \"...\"; return \"...\";
}); });
var x: number = array[0]; var x: number = array[0]; // error: string !~> number
} }
var Foo = require(\"./genericfoo\"); var Foo = require(\"./genericfoo\");
var foo = new Foo(); var foo = new Foo();
function g() { function g() {
@ -39,9 +38,9 @@ function g() {
return \"...\"; return \"...\";
}); });
var x: number = foo1.get(); var x: number = foo1.get();
// error: string !~> number
foo = foo1; foo = foo1;
} }"
"
`; `;
exports[`test genericfoo.js 1`] = ` exports[`test genericfoo.js 1`] = `
@ -68,6 +67,6 @@ class Foo<T> {
return this.x; return this.x;
} }
} }
module.exports = Foo;
" module.exports = Foo;"
`; `;

View File

@ -31,31 +31,35 @@ function f(): number {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// You should be able to call objects with call properties // You should be able to call objects with call properties
// ...and get an error if the return type is wrong
// ...or if the param type is wrong
// ...or if the arity is wrong
// ...or if there is no call property
// Make sure we complain even if the object literal is unsealed.
function a(f: { (): string }, g: { (x: number): string }): string { function a(f: { (): string }, g: { (x: number): string }): string {
return f() + g(123); return f() + g(123);
} }
// ...and get an error if the return type is wrong
function b(f: { (): string }): number { function b(f: { (): string }): number {
return f(); return f();
} }
// ...or if the param type is wrong
function c(f: { (x: number): number }): number { function c(f: { (x: number): number }): number {
return f(\"hello\"); return f(\"hello\");
} }
// ...or if the arity is wrong
function d(f: { (x: number): number }): number { function d(f: { (x: number): number }): number {
return f(); return f();
} }
// ...or if there is no call property
function e(f: {}): number { function e(f: {}): number {
return f(); return f();
} }
// Make sure we complain even if the object literal is unsealed.
function f(): number { function f(): number {
var x = {}; var x = {};
return x(); return x();
} }"
"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
@ -81,38 +85,41 @@ var y : {} = function (x: number): string { return \"hi\"; };
var z : Object = function (x: number): string { return \"hi\"; }; var z : Object = function (x: number): string { return \"hi\"; };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// You should be able to use a function as an object with a call property // You should be able to use a function as an object with a call property
// ...and it should notice when the return type is wrong
// ...or if the param type is wrong
// ...or if the arity is wrong
// ...but subtyping rules still apply
// arity
// return type
// param type
// A function can be an object
var a: { (x: number): string } = function(x: number): string { var a: { (x: number): string } = function(x: number): string {
return \"hi\"; return \"hi\";
}; };
// ...and it should notice when the return type is wrong
var b: { (x: number): number } = function(x: number): string { var b: { (x: number): number } = function(x: number): string {
return \"hi\"; return \"hi\";
}; };
// ...or if the param type is wrong
var c: { (x: string): string } = function(x: number): string { var c: { (x: string): string } = function(x: number): string {
return \"hi\"; return \"hi\";
}; };
// ...or if the arity is wrong
var d: { (): string } = function(x: number): string { var d: { (): string } = function(x: number): string {
return \"hi\"; return \"hi\";
}; };
// ...but subtyping rules still apply
var e: { (x: any): void } = function() {}; var e: { (x: any): void } = function() {};
// arity
var f: { (): mixed } = function(): string { var f: { (): mixed } = function(): string {
return \"hi\"; return \"hi\";
}; };
// return type
var g: { (x: string): void } = function(x: mixed) {}; var g: { (x: string): void } = function(x: mixed) {};
// param type
// A function can be an object
var y: {} = function(x: number): string { var y: {} = function(x: number): string {
return \"hi\"; return \"hi\";
}; };
var z: Object = function(x: number): string { var z: Object = function(x: number): string {
return \"hi\"; return \"hi\";
}; };"
"
`; `;
exports[`test C.js 1`] = ` exports[`test C.js 1`] = `
@ -152,35 +159,39 @@ function g(x: {}): Function {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// You should be able to use an object as a function // You should be able to use an object as a function
// ...and it should notice when the return type is wrong
// ...or if the param type is wrong
// ...or if the arity is wrong
// ...or if it doesn\'t have a call property
// AnyFunT should also be allowed
// ... but only if the object is callable
// error
function a(x: { (z: number): string }): (z: number) => string { function a(x: { (z: number): string }): (z: number) => string {
return x; return x;
} }
// ...and it should notice when the return type is wrong
function b(x: { (z: number): string }): (z: number) => number { function b(x: { (z: number): string }): (z: number) => number {
return x; return x;
} }
// ...or if the param type is wrong
function c(x: { (z: number): string }): (z: string) => string { function c(x: { (z: number): string }): (z: string) => string {
return x; return x;
} }
// ...or if the arity is wrong
function d(x: { (z: number): string }): () => string { function d(x: { (z: number): string }): () => string {
return x; return x;
} }
// ...or if it doesn\'t have a call property
function e(x: {}): () => string { function e(x: {}): () => string {
return x; return x;
} }
// AnyFunT should also be allowed
function f(x: { (z: number): string }): Function { function f(x: { (z: number): string }): Function {
return x; return x;
} }
// ... but only if the object is callable
function g(x: {}): Function { function g(x: {}): Function {
return x; return x; // error
} }"
"
`; `;
exports[`test D.js 1`] = ` exports[`test D.js 1`] = `
@ -208,26 +219,29 @@ function e(x: { (): string; (x: number): string }): () => number {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Multiple call properties should also be supported // Multiple call properties should also be supported
// It should be fine when a function satisfies them all
// ...but should notice when a function doesn\'t satisfy them all
// Only one call property needs to match the function
// ...but you need at least one
function a(f: { (): string, (x: number): string }): string { function a(f: { (): string, (x: number): string }): string {
return f() + f(123); return f() + f(123);
} }
// It should be fine when a function satisfies them all
var b: { (): string, (x: number): string } = function(x?: number): string { var b: { (): string, (x: number): string } = function(x?: number): string {
return \"hi\"; return \"hi\";
}; };
// ...but should notice when a function doesn\'t satisfy them all
var c: { (): string, (x: number): string } = function(x: number): string { var c: { (): string, (x: number): string } = function(x: number): string {
return \"hi\"; return \"hi\";
}; };
// Only one call property needs to match the function
function d(x: { (): string, (x: number): string }): () => string { function d(x: { (): string, (x: number): string }): () => string {
return x; return x;
} }
// ...but you need at least one
function e(x: { (): string, (x: number): string }): () => number { function e(x: { (): string, (x: number): string }): () => number {
return x; return x;
} }"
"
`; `;
exports[`test E.js 1`] = ` exports[`test E.js 1`] = `
@ -243,14 +257,15 @@ f.myProp = 123;
var c : { myProp: number } = f; var c : { myProp: number } = f;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Expecting properties that don\'t exist should be an error // Expecting properties that don\'t exist should be an error
// Expecting properties that do exist should be fine
// Expecting properties in the functions statics should be fine
var a: { someProp: number } = function() {}; var a: { someProp: number } = function() {};
// Expecting properties that do exist should be fine
var b: { apply: Function } = function() {}; var b: { apply: Function } = function() {};
// Expecting properties in the functions statics should be fine
var f = function() {}; var f = function() {};
f.myProp = 123; f.myProp = 123;
var c: { myProp: number } = f; var c: { myProp: number } = f;"
"
`; `;
exports[`test F.js 1`] = ` exports[`test F.js 1`] = `
@ -277,24 +292,28 @@ var y : {} = (x) => \"hi\"
var z : Object = (x) => \"hi\" var z : Object = (x) => \"hi\"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// You should be able to use an arrow function as an object with a call property // You should be able to use an arrow function as an object with a call property
// ...and it should notice when the return type is wrong
// ...or if the param type is wrong
// ...or if the arity is wrong
// ...but subtyping rules still apply
// arity
// return type
// param type (date < number)
// A function can be an object
var a: { (x: number): string } = x => x.toString(); var a: { (x: number): string } = x => x.toString();
// ...and it should notice when the return type is wrong
var b: { (x: number): number } = x => \"hi\"; var b: { (x: number): number } = x => \"hi\";
// ...or if the param type is wrong
var c: { (x: string): string } = x => x.toFixed(); var c: { (x: string): string } = x => x.toFixed();
// ...or if the arity is wrong
var d: { (): string } = x => \"hi\"; var d: { (): string } = x => \"hi\";
// ...but subtyping rules still apply
var e: { (x: any): void } = () => {}; var e: { (x: any): void } = () => {};
// arity
var f: { (): mixed } = () => \"hi\"; var f: { (): mixed } = () => \"hi\";
// return type
var g: { (x: Date): void } = x => { var g: { (x: Date): void } = x => {
x * 2; x * 2;
}; };
// param type (date < number)
// A function can be an object
var y: {} = x => \"hi\"; var y: {} = x => \"hi\";
var z: Object = x => \"hi\"; var z: Object = x => \"hi\";"
"
`; `;

View File

@ -11,11 +11,12 @@ function f(x) {
(f: F); (f: F);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
type F = { (x: string): number, p?: string }; type F = { (x: string): number, p?: string };
function f(x) { function f(x) {
return x.length; return x.length;
} }
(f: F);
" (f: F);"
`; `;
exports[`test primitives.js 1`] = ` exports[`test primitives.js 1`] = `
@ -41,23 +42,23 @@ declare var callable: Callable;
callable(0); // error, number ~> string callable(0); // error, number ~> string
callable.call(null, 0); // error, number ~> string callable.call(null, 0); // error, number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, callable signature not found
// error, number ~> string
// error, number ~> string
// error, number ~> string
// error, number ~> string
var x = Boolean(4); var x = Boolean(4);
function foo(fn: (value: any) => boolean) {} function foo(fn: (value: any) => boolean) {}
foo(Boolean); foo(Boolean);
var dict: { [k: string]: any } = {}; var dict: { [k: string]: any } = {};
dict(); dict();
// error, callable signature not found
interface ICall { (x: string): void } interface ICall { (x: string): void }
declare var icall: ICall; declare var icall: ICall;
icall(0); icall(0);
// error, number ~> string
icall.call(null, 0); icall.call(null, 0);
// error, number ~> string
type Callable = { (x: string): void }; type Callable = { (x: string): void };
declare var callable: Callable; declare var callable: Callable;
callable(0); callable(0);
callable.call(null, 0); // error, number ~> string
" callable.call(null, 0); // error, number ~> string"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test not_flow.js 1`] = ` exports[`test not_flow.js 1`] = `
"1 * \'foo\'; "1 * \'foo\';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 * \"foo\"; 1 * \"foo\";"
"
`; `;

View File

@ -18,18 +18,18 @@ class Bar extends Foo {
/** /**
* @flow * @flow
*/ */
// error
class Foo { class Foo {
_method(): string { _method(): string {
return \"this is private\"; return \"this is private\";
} }
} }
class Bar extends Foo { class Bar extends Foo {
test() { test() {
(this._method(): string); (this._method(): string); // error
} }
} }"
"
`; `;
exports[`test without_munging.js 1`] = ` exports[`test without_munging.js 1`] = `
@ -54,16 +54,16 @@ class Bar extends Foo {
* @flow * @flow
* @preventMunge * @preventMunge
*/ */
// ok
class Foo { class Foo {
_method(): string { _method(): string {
return \"this is not private\"; return \"this is not private\";
} }
} }
class Bar extends Foo { class Bar extends Foo {
test() { test() {
(this._method(): string); (this._method(): string); // ok
} }
} }"
"
`; `;

View File

@ -61,19 +61,6 @@ module.exports = {
A: A, B: B, C: C, D: D, E: E A: A, B: B, C: C, D: D, E: E
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error?
// error?
// error?
// error
// error
// error
// error
// error
// error B ~> number
// error?
// error
// error
// note: above classdefs are sufficiently annotated to export
class A { class A {
static x: number; static x: number;
static y: string; static y: string;
@ -81,25 +68,34 @@ class A {
static bar(y: string) {} static bar(y: string) {}
} }
A.qux = function(x: string) {}; A.qux = function(x: string) {};
// error?
class B extends A { class B extends A {
static x: string; static x: string;
// error?
static foo(x: string) {} static foo(x: string) {}
// error?
static main() { static main() {
B.x = 0; B.x = 0;
// error
B.x = \"\"; B.x = \"\";
B.foo(0); B.foo(0);
// error
B.foo(\"\"); B.foo(\"\");
B.y = 0; B.y = 0;
// error
B.bar(0); B.bar(0);
B.qux(0); // error
B.qux(0); // error
} }
static create(): A { static create(): A {
return new this(); return new this();
} }
static badCreate(): number { static badCreate(): number {
return new this(); return new this(); // error B ~> number
} }
} }
class C<X> { class C<X> {
static x: X; static x: X;
static bar(x: X) {} static bar(x: X) {}
@ -107,22 +103,28 @@ class C<X> {
return new this(); return new this();
} }
} }
class D extends C<string> { class D extends C<string> {
static main() { static main() {
D.foo(0); D.foo(0);
// error?
D.bar(0); D.bar(0);
} }
} }
var d: C<*> = D.create(); var d: C<*> = D.create();
(new A(): typeof A); (new A(): typeof A);
(B: typeof A); (B: typeof A);
class E { class E {
static x: number; static x: number;
static foo(): string { static foo(): string {
this.bar(); this.bar();
return this.x; // error
return this.x; // error
} }
} }
module.exports = { A: A, B: B, C: C, D: D, E: E };
" // note: above classdefs are sufficiently annotated to export
module.exports = { A: A, B: B, C: C, D: D, E: E };"
`; `;

View File

@ -8,8 +8,8 @@ module.exports = { A, B };
/* @flow */ /* @flow */
class A {} class A {}
class B {} class B {}
module.exports = { A, B };
" module.exports = { A, B };"
`; `;
exports[`test test2.js 1`] = ` exports[`test test2.js 1`] = `
@ -23,10 +23,11 @@ var y: I.B = new C();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
var I = require(\"./test.js\"); var I = require(\"./test.js\");
class C extends I.A {} class C extends I.A {}
var x: I.A = new C(); var x: I.A = new C();
var y: I.B = new C(); var y: I.B = new C();"
"
`; `;
exports[`test test3.js 1`] = ` exports[`test test3.js 1`] = `
@ -37,14 +38,13 @@ class C<X, Y, Z> extends B {}
var c: C<number, string, Array<bool>> = new C; // none of the type args matter var c: C<number, string, Array<bool>> = new C; // none of the type args matter
var a: A<string, number, Array<bool>> = c; // the third type arg is incorrect var a: A<string, number, Array<bool>> = c; // the third type arg is incorrect
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// none of the type args matter
// the third type arg is incorrect
class A<X, Y, Z> {} class A<X, Y, Z> {}
class B extends A<string, number, boolean> {} class B extends A<string, number, boolean> {}
class C<X, Y, Z> extends B {} class C<X, Y, Z> extends B {}
var c: C<number, string, Array<boolean>> = new C(); var c: C<number, string, Array<boolean>> = new C();
var a: A<string, number, Array<boolean>> = c; // none of the type args matter
" var a: A<string, number, Array<boolean>> = c; // the third type arg is incorrect"
`; `;
exports[`test test4.js 1`] = ` exports[`test test4.js 1`] = `
@ -65,14 +65,18 @@ foo(new D, { f_: 0 });
class C<X> { class C<X> {
x: X; x: X;
} }
function foo<X>(c: C<X>, x: X) {} function foo<X>(c: C<X>, x: X) {}
type O = { f: number }; type O = { f: number };
foo((new C(): C<O>), { f_: 0 }); foo((new C(): C<O>), { f_: 0 });
class D extends C<O> { class D extends C<O> {
bar() { bar() {
this.x; this.x;
} }
} }
foo(new D(), { f_: 0 });
" foo(new D(), { f_: 0 });"
`; `;

View File

@ -11,19 +11,17 @@ function bar(x: Class<B>): B {
return new x(); // error (too few args) return new x(); // error (too few args)
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// OK
// error (too few args)
class A {} class A {}
function foo(x: Class<A>): A { function foo(x: Class<A>): A {
return new x(); return new x(); // OK
} }
class B { class B {
constructor(_: any) {} constructor(_: any) {}
} }
function bar(x: Class<B>): B { function bar(x: Class<B>): B {
return new x(); return new x(); // error (too few args)
} }"
"
`; `;
exports[`test test2.js 1`] = ` exports[`test test2.js 1`] = `
@ -46,13 +44,14 @@ check(B, new C);
// makes it useless in such a function (when limited to classes and instances), // makes it useless in such a function (when limited to classes and instances),
// since everything can be trivially satisfied by going to \`mixed\`. // since everything can be trivially satisfied by going to \`mixed\`.
declare function check<X>(cls: $Type<X>, inst: X): void; declare function check<X>(cls: $Type<X>, inst: X): void;
class A {} class A {}
class B extends A {} class B extends A {}
class C {} class C {}
check(B, new A()); check(B, new A());
check(A, new B()); check(A, new B());
check(C, new A()); check(C, new A());
check(C, new B()); check(C, new B());
check(B, new C()); check(B, new C());"
"
`; `;

View File

@ -8,8 +8,8 @@ module.exports = A;
class A { class A {
foo(x: number): void {} foo(x: number): void {}
} }
module.exports = A;
" module.exports = A;"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
@ -22,13 +22,14 @@ let b = new B();
module.exports = B; module.exports = B;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, number !~> function
var A = require(\"./A\"); var A = require(\"./A\");
class B extends A {} class B extends A {}
let b = new B(); let b = new B();
(b.foo: number); (b.foo: number);
module.exports = B; // error, number !~> function
" module.exports = B;"
`; `;
exports[`test C.js 1`] = ` exports[`test C.js 1`] = `
@ -43,15 +44,16 @@ let c = new C();
module.exports = C; module.exports = C;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, number !~> function
var B = require(\"./B\"); var B = require(\"./B\");
class C extends B { class C extends B {
foo(x: string): void {} foo(x: string): void {}
} }
let c = new C(); let c = new C();
(c.foo: number); (c.foo: number);
module.exports = C; // error, number !~> function
" module.exports = C;"
`; `;
exports[`test D.js 1`] = ` exports[`test D.js 1`] = `
@ -61,8 +63,7 @@ new E().x
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class D {} class D {}
class E {} class E {}
new E().x; new E().x;"
"
`; `;
exports[`test class_shapes.js 1`] = ` exports[`test class_shapes.js 1`] = `
@ -103,42 +104,48 @@ var z = new Test2Class();
var w : Foo = z; var w : Foo = z;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// exists in TestClass
// doesn\'t exist type Foo = {
// exists in TestClass, optional a: string,
/* doesn\'t exist*/ // exists in TestClass
// ok b: string,
// error, TestClass has no b // doesn\'t exist
// ok c?: ?string,
// error, TestClass has no d // exists in TestClass, optional
// error, doesn\'t exist in TestClass d?: number /* doesn\'t exist*/
// ok, it\'s optional };
// conflicts with cast to Foo
// conflicts with cast to Foo
// conflicts with cast to Foo
type Foo = { a: string, b: string, c?: ?string, d?: number };
class TestClass { class TestClass {
a: string; a: string;
c: ?string; c: ?string;
} }
var x = new TestClass(); var x = new TestClass();
x.a; x.a;
// ok
x.b; x.b;
// error, TestClass has no b
x.c; x.c;
// ok
x.d; x.d;
// error, TestClass has no d
var y: Foo = x; var y: Foo = x;
y.b; y.b;
// error, doesn\'t exist in TestClass
y.d; y.d;
// ok, it\'s optional
class Test2Superclass { class Test2Superclass {
a: number; a: number;
c: ?number; // conflicts with cast to Foo
c: ?number; // conflicts with cast to Foo
} }
class Test2Class extends Test2Superclass { class Test2Class extends Test2Superclass {
b: number; b: number; // conflicts with cast to Foo
} }
var z = new Test2Class(); var z = new Test2Class();
var w: Foo = z; var w: Foo = z;"
"
`; `;
exports[`test expr.js 1`] = ` exports[`test expr.js 1`] = `
@ -173,30 +180,29 @@ var _Alias = class Alias {
var alias1: Alias = new _Alias(); // error: bad pun var alias1: Alias = new _Alias(); // error: bad pun
var alias2: Alias = _Alias.factory(); // error: bad pun var alias2: Alias = _Alias.factory(); // error: bad pun
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// OK: Foo is a type in this scope var Bar = class Foo {
// OK: Foo is a runtime binding in this scope static factory(): Foo {
// OK: Foo is a type in this scope
return new Foo(); // OK: Foo is a runtime binding in this scope
}
};
var bar1: Bar = new Bar();
// OK // OK
var bar2: Bar = Bar.factory();
// OK // OK
// NB: Don\'t write expected errors using Foo to avoid error collapse hiding an // NB: Don\'t write expected errors using Foo to avoid error collapse hiding an
// unexpected failure in the above code. // unexpected failure in the above code.
// error: Baz is not a runtime binding in this scope
// error: Qux is not a type in this scope
// OK: anon classes create no binding, but can be bound manually
// error: bad pun
// error: bad pun
var Bar = class Foo {
static factory(): Foo {
return new Foo();
}
};
var bar1: Bar = new Bar();
var bar2: Bar = Bar.factory();
var B = class Baz {}; var B = class Baz {};
var b = new Baz(); var b = new Baz();
// error: Baz is not a runtime binding in this scope
var C = class Qux {}; var C = class Qux {};
var c: Qux = new C(); var c: Qux = new C();
// error: Qux is not a type in this scope
// OK: anon classes create no binding, but can be bound manually
var Anon = class {}; var Anon = class {};
var anon: Anon = new Anon(); var anon: Anon = new Anon();
class Alias {} class Alias {}
var _Alias = class Alias { var _Alias = class Alias {
static factory(): Alias { static factory(): Alias {
@ -204,8 +210,8 @@ var _Alias = class Alias {
} }
}; };
var alias1: Alias = new _Alias(); var alias1: Alias = new _Alias();
var alias2: Alias = _Alias.factory(); // error: bad pun
" var alias2: Alias = _Alias.factory(); // error: bad pun"
`; `;
exports[`test loc.js 1`] = ` exports[`test loc.js 1`] = `
@ -216,10 +222,10 @@ type Foo = number
class Foo {} // error, shadows type Foo class Foo {} // error, shadows type Foo
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error, shadows type Foo
type Foo = number; type Foo = number;
class Foo {}
" class Foo {} // error, shadows type Foo"
`; `;
exports[`test statics.js 1`] = ` exports[`test statics.js 1`] = `
@ -238,17 +244,17 @@ declare var o: {p:number};
(o: Class<C>); // error, object type incompatible with class type (o: Class<C>); // error, object type incompatible with class type
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Class static fields are compatible with object types
// ok
// errors, string ~> number & vice versa (unify)
// error, object type incompatible with class type
class C { class C {
static p: string; static p: string;
} }
C.p = \"hi\"; C.p = \"hi\";
// Class static fields are compatible with object types
(C: { p: string }); (C: { p: string });
// ok
(C: { p: number }); (C: { p: number });
// errors, string ~> number & vice versa (unify)
declare var o: { p: number }; declare var o: { p: number };
(o: Class<C>); (o: Class<C>); // error, object type incompatible with class type"
"
`; `;

View File

@ -84,76 +84,84 @@ function local_meth() {
* Test tracking of variable types across closure calls. * Test tracking of variable types across closure calls.
* @flow * @flow
*/ */
function takes_string(_: string) {}
// global write from function // global write from function
// //
// ok
// error
// shouldn\'t pollute linear refinement
// local write from function
//
// ok
// error
// shouldn\'t pollute linear refinement
// global write from method
//
// ok
// error
// shouldn\'t pollute linear refinement
// local write from method
//
// ok
// error
// shouldn\'t pollute linear refinement
function takes_string(_: string) {}
var global_x = \"hello\"; var global_x = \"hello\";
function global_f() {} function global_f() {}
function global_g() { function global_g() {
global_x = 42; global_x = 42;
} }
global_f(); global_f();
takes_string(global_x); takes_string(global_x);
// ok
global_g(); global_g();
takes_string(global_x); takes_string(global_x);
// error
global_x = 42; global_x = 42;
// shouldn\'t pollute linear refinement
// local write from function
//
function local_func() { function local_func() {
var local_x = \"hello\"; var local_x = \"hello\";
function local_f() {} function local_f() {}
function local_g() { function local_g() {
local_x = 42; local_x = 42;
} }
local_f(); local_f();
takes_string(local_x); takes_string(local_x);
// ok
local_g(); local_g();
takes_string(local_x); takes_string(local_x);
local_x = 42; // error
local_x = 42; // shouldn\'t pollute linear refinement
} }
// global write from method
//
var global_y = \"hello\"; var global_y = \"hello\";
var global_o = { var global_o = {
f: function() {}, f: function() {},
g: function() { g: function() {
global_y = 42; global_y = 42;
} }
}; };
global_o.f(); global_o.f();
takes_string(global_y); takes_string(global_y);
// ok
global_o.g(); global_o.g();
takes_string(global_y); takes_string(global_y);
// error
global_y = 42; global_y = 42;
// shouldn\'t pollute linear refinement
// local write from method
//
function local_meth() { function local_meth() {
var local_y = \"hello\"; var local_y = \"hello\";
var local_o = { var local_o = {
f: function() {}, f: function() {},
g: function() { g: function() {
local_y = 42; local_y = 42;
} }
}; };
local_o.f(); local_o.f();
takes_string(local_y); takes_string(local_y);
// ok
local_o.g(); local_o.g();
takes_string(local_y); takes_string(local_y);
local_y = 42; // error
} local_y = 42; // shouldn\'t pollute linear refinement
" }"
`; `;
exports[`test cond_havoc.js 1`] = ` exports[`test cond_havoc.js 1`] = `
@ -172,10 +180,10 @@ function example(b: bool): number {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// from sam, https://github.com/facebook/flow/issues/780 // from sam, https://github.com/facebook/flow/issues/780
// call to f() within if should properly havoc x. // call to f() within if should properly havoc x.
// //
// error, string ~/~> number (return type anno) TODO
function example(b: boolean): number { function example(b: boolean): number {
var x = 0; var x = 0;
function f() { function f() {
@ -184,9 +192,8 @@ function example(b: boolean): number {
if (b) { if (b) {
f(); f();
} }
return x; return x; // error, string ~/~> number (return type anno) TODO
} }"
"
`; `;
exports[`test const.js 1`] = ` exports[`test const.js 1`] = `
@ -242,63 +249,61 @@ call_me();
* consts retain refinements * consts retain refinements
* @flow * @flow
*/ */
// global, anybody can call it at any time // global, anybody can call it at any time
// ok: if const_x is truthy here, it\'s truthy everywhere
// error: var_x might no longer be truthy when call_me is called
// error
// ok
// ok
// ok
// error
// error
// error
// in a galaxy far far away
var call_me: () => void = () => {}; var call_me: () => void = () => {};
function g(x: ?number) { function g(x: ?number) {
const const_x = x; const const_x = x;
if (const_x) { if (const_x) {
// ok: if const_x is truthy here, it\'s truthy everywhere
call_me = () => { call_me = () => {
var y: number = const_x; var y: number = const_x;
}; };
} }
var var_x = x; var var_x = x;
if (var_x) { if (var_x) {
// error: var_x might no longer be truthy when call_me is called
call_me = () => { call_me = () => {
var y: number = var_x; var y: number = var_x;
}; }; // error
} }
var_x = null; var_x = null;
} }
function h(x: number | string | boolean) { function h(x: number | string | boolean) {
const const_x = x; const const_x = x;
if (typeof const_x == \"number\") { if (typeof const_x == \"number\") {
call_me = () => { call_me = () => {
var y: number = const_x; var y: number = const_x;
}; }; // ok
} else if (typeof const_x == \"string\") { } else if (typeof const_x == \"string\") {
call_me = () => { call_me = () => {
var y: string = const_x; var y: string = const_x;
}; }; // ok
} else if (typeof const_x == \"boolean\") { } else if (typeof const_x == \"boolean\") {
call_me = () => { call_me = () => {
var y: boolean = const_x; var y: boolean = const_x;
}; }; // ok
} }
var var_x = x; var var_x = x;
if (typeof var_x == \"number\") { if (typeof var_x == \"number\") {
call_me = () => { call_me = () => {
var y: number = var_x; var y: number = var_x;
}; }; // error
} else if (typeof var_x == \"string\") { } else if (typeof var_x == \"string\") {
call_me = () => { call_me = () => {
var y: string = var_x; var y: string = var_x;
}; }; // error
} else if (typeof var_x == \"boolean\") { } else if (typeof var_x == \"boolean\") {
call_me = () => { call_me = () => {
var y: boolean = var_x; var y: boolean = var_x;
}; }; // error
} }
} }
call_me();
" // in a galaxy far far away
call_me();"
`; `;

View File

@ -5,8 +5,8 @@ function f(x:string) { }
module.exports = f; module.exports = f;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function f(x: string) {} function f(x: string) {}
module.exports = f;
" module.exports = f;"
`; `;
exports[`test Rel.js 1`] = ` exports[`test Rel.js 1`] = `
@ -16,6 +16,6 @@ var f = require(\'./Abs\');
f(0); f(0);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var f = require(\"./Abs\"); var f = require(\"./Abs\");
f(0);
" f(0);"
`; `;

View File

@ -23,19 +23,21 @@ ColorIdToNumber.XXX; // oops
module.exports = { ColorId, ColorNumber }; module.exports = { ColorId, ColorNumber };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// oops
// oops
var ColorId = { RED: \"R\", GREEN: \"G\", BLUE: \"B\" }; var ColorId = { RED: \"R\", GREEN: \"G\", BLUE: \"B\" };
var ColorNumber = { RED: \"ff0000\", GREEN: \"00ff00\", BLUE: \"0000ff\" }; var ColorNumber = { RED: \"ff0000\", GREEN: \"00ff00\", BLUE: \"0000ff\" };
var ColorIdToNumber = { var ColorIdToNumber = {
[ColorId.RED]: ColorNumber.RED, [ColorId.RED]: ColorNumber.RED,
[ColorId.GREEN]: ColorNumber.GREEN, [ColorId.GREEN]: ColorNumber.GREEN,
[ColorId.BLUE]: ColorNumber.BLUE [ColorId.BLUE]: ColorNumber.BLUE
}; };
(ColorIdToNumber[ColorId.RED]: \"ffffff\"); (ColorIdToNumber[ColorId.RED]: \"ffffff\");
// oops
ColorIdToNumber.XXX; ColorIdToNumber.XXX;
module.exports = { ColorId, ColorNumber }; // oops
" module.exports = { ColorId, ColorNumber };"
`; `;
exports[`test test2.js 1`] = ` exports[`test test2.js 1`] = `
@ -50,16 +52,16 @@ var ColorIdToNumber = {
module.exports = ColorIdToNumber; module.exports = ColorIdToNumber;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// oops
var { ColorId, ColorNumber } = require(\"./test\"); var { ColorId, ColorNumber } = require(\"./test\");
var ColorIdToNumber = { var ColorIdToNumber = {
[ColorId.RED]: ColorNumber.RED, [ColorId.RED]: ColorNumber.RED,
[ColorId.GREEN]: ColorNumber.GREEN, [ColorId.GREEN]: ColorNumber.GREEN,
[ColorId.BLUE]: ColorNumber.BLUE [ColorId.BLUE]: ColorNumber.BLUE
}; };
(ColorIdToNumber[ColorId.GREEN]: \"ffffff\"); (ColorIdToNumber[ColorId.GREEN]: \"ffffff\");
module.exports = ColorIdToNumber; // oops
" module.exports = ColorIdToNumber;"
`; `;
exports[`test test3.js 1`] = ` exports[`test test3.js 1`] = `
@ -68,18 +70,16 @@ var ColorIdToNumber = require(\'./test2\');
(ColorIdToNumber[ColorId.BLUE]: \'ffffff\'); // oops (ColorIdToNumber[ColorId.BLUE]: \'ffffff\'); // oops
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// oops
var { ColorId } = require(\"./test\"); var { ColorId } = require(\"./test\");
var ColorIdToNumber = require(\"./test2\"); var ColorIdToNumber = require(\"./test2\");
(ColorIdToNumber[ColorId.BLUE]: \"ffffff\");
" (ColorIdToNumber[ColorId.BLUE]: \"ffffff\"); // oops"
`; `;
exports[`test test4.js 1`] = ` exports[`test test4.js 1`] = `
"module.exports = \'hello\'; "module.exports = \'hello\';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
module.exports = \"hello\"; module.exports = \"hello\";"
"
`; `;
exports[`test test5.js 1`] = ` exports[`test test5.js 1`] = `
@ -93,18 +93,15 @@ module.exports = {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var hello = require(\"./test4\"); var hello = require(\"./test4\");
var dummy = require(\"./test\"); var dummy = require(\"./test\");
module.exports = { ...dummy, [hello]: \"world\", ...dummy }; module.exports = { ...dummy, [hello]: \"world\", ...dummy };"
"
`; `;
exports[`test test6.js 1`] = ` exports[`test test6.js 1`] = `
"var o = require(\'./test5\'); "var o = require(\'./test5\');
(o.hello: \'nothing\'); // oops (o.hello: \'nothing\'); // oops
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// oops
var o = require(\"./test5\"); var o = require(\"./test5\");
(o.hello: \"nothing\"); (o.hello: \"nothing\"); // oops"
"
`; `;
exports[`test test7.js 1`] = ` exports[`test test7.js 1`] = `
@ -114,8 +111,6 @@ var x: string = obj[\'m\'](); // error, number ~> string
var arr = [function() { return this.length }]; var arr = [function() { return this.length }];
var y: string = arr[0](); // error: number ~> string var y: string = arr[0](); // error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, number ~> string
// error: number ~> string
var obj = { var obj = {
x: 0, x: 0,
m() { m() {
@ -123,11 +118,11 @@ var obj = {
} }
}; };
var x: string = obj[\"m\"](); var x: string = obj[\"m\"]();
// error, number ~> string
var arr = [ var arr = [
function() { function() {
return this.length; return this.length;
} }
]; ];
var y: string = arr[0](); var y: string = arr[0](); // error: number ~> string"
"
`; `;

View File

@ -25,25 +25,28 @@ function d(): string { // expected \`: number | boolean\`
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// equivalent to \`return (x && 1) || 0\`
// expected \`: number | boolean\`
// equivalent to \`return x != null && x\`
function a(): number { function a(): number {
var x: ?string = null; var x: ?string = null;
return x ? 1 : 0; return x ? 1 : 0;
} }
function b(): number { function b(): number {
var x: ?number = null; var x: ?number = null;
return x != null ? x : 0; return x != null ? x : 0;
} }
function c(): number { function c(): number {
// equivalent to \`return (x && 1) || 0\`
var x = false; var x = false;
var temp = x ? 1 : x; var temp = x ? 1 : x;
return temp ? temp : 0; return temp ? temp : 0;
} }
function d(): string { function d(): string {
// expected \`: number | boolean\`
// equivalent to \`return x != null && x\`
var x: ?number = null; var x: ?number = null;
return x != null ? x : x != null; return x != null ? x : x != null;
} }"
"
`; `;

View File

@ -1,7 +1,5 @@
exports[`test no_at_flow.js 1`] = ` exports[`test no_at_flow.js 1`] = `
"var x: number = \"not a number\"; // Error: string ~> number "var x: number = \"not a number\"; // Error: string ~> number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Error: string ~> number var x: number = \"not a number\"; // Error: string ~> number"
var x: number = \"not a number\";
"
`; `;

View File

@ -1,7 +1,5 @@
exports[`test no_at_flow.js 1`] = ` exports[`test no_at_flow.js 1`] = `
"var x: number = \"not a number\"; // No error "var x: number = \"not a number\"; // No error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// No error var x: number = \"not a number\"; // No error"
var x: number = \"not a number\";
"
`; `;

View File

@ -4,6 +4,6 @@ exports[`test no_at_flow.js 1`] = `
x.length; x.length;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var x; var x;
x.length;
" x.length;"
`; `;

View File

@ -14,11 +14,12 @@ foo(\'Hello, world!\');
/* /*
* @flow * @flow
*/ */
// This file should be ignored, so this should not result in an error
function foo(x) { function foo(x) {
var a: number = \"asdf\"; var a: number = \"asdf\";
return x * 10; return x * 10;
} }
foo(\"Hello, world!\");
" // This file should be ignored, so this should not result in an error
foo(\"Hello, world!\");"
`; `;

View File

@ -5,7 +5,7 @@ exports[`test foo.js 1`] = `
var x: number = \"string\"; var x: number = \"string\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// No error, this file is ignored // No error, this file is ignored
var x: number = \"string\"; var x: number = \"string\";"
"
`; `;

View File

@ -4,7 +4,6 @@ exports[`test foo.js 1`] = `
var x: number = \"string\"; // Error string ~> number var x: number = \"string\"; // Error string ~> number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Error string ~> number
var x: number = \"string\"; var x: number = \"string\"; // Error string ~> number"
"
`; `;

View File

@ -7,9 +7,9 @@ var a: number = test;
var b: string = test; // Error: number ~> string var b: string = test; // Error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// Error: number ~> string
import {test} from \"testmodule\"; import {test} from \"testmodule\";
var a: number = test; var a: number = test;
var b: string = test; var b: string = test; // Error: number ~> string"
"
`; `;

View File

@ -4,6 +4,6 @@ exports[`test testmodule.js 1`] = `
export let test = 42; export let test = 42;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
export let test = 42;
" export let test = 42;"
`; `;

View File

@ -5,8 +5,7 @@ import {className} from \"./SomeCSSFile.css\";
import {doesntExist} from \"./SomeCSSFile.css\"; // Error: \`doestExist\` isn\'t an export import {doesntExist} from \"./SomeCSSFile.css\"; // Error: \`doestExist\` isn\'t an export
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// Error: \`doestExist\` isn\'t an export
import {className} from \"./SomeCSSFile.css\"; import {className} from \"./SomeCSSFile.css\";
import {doesntExist} from \"./SomeCSSFile.css\"; import {doesntExist} from \"./SomeCSSFile.css\"; // Error: \`doestExist\` isn\'t an export"
"
`; `;

View File

@ -14,19 +14,19 @@ var m2 = require(\'2DoesntExist\'); // Error
import {numVal as numVal2} from \'3DoesntExist\'; // Error import {numVal as numVal2} from \'3DoesntExist\'; // Error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Error: \'Exists2\' is not a valid module name
//
// This tests that, for haste, the first name_mapper regexp that happens to
// match the given module name string is picked.
// Error
// Error
var m1 = require(\"1DoesntExist\"); var m1 = require(\"1DoesntExist\");
import {numVal as numVal1} from \"1DoesntExist\"; import {numVal as numVal1} from \"1DoesntExist\";
var a_1: number = m1.numVal; var a_1: number = m1.numVal;
var a_2: number = numVal1; var a_2: number = numVal1;
// Error: \'Exists2\' is not a valid module name
//
// This tests that, for haste, the first name_mapper regexp that happens to
// match the given module name string is picked.
var m2 = require(\"2DoesntExist\"); var m2 = require(\"2DoesntExist\");
import {numVal as numVal2} from \"3DoesntExist\"; // Error
" import {numVal as numVal2} from \"3DoesntExist\"; // Error"
`; `;
exports[`test Exists.js 1`] = ` exports[`test Exists.js 1`] = `
@ -43,6 +43,6 @@ module.exports = {
* @providesModule Exists * @providesModule Exists
* @flow * @flow
*/ */
module.exports = { numVal: 42 };
" module.exports = { numVal: 42 };"
`; `;

View File

@ -26,34 +26,33 @@ var c_3: number = numVal3;
var c_4: string = numVal3; // Error: number ~> string var c_4: string = numVal3; // Error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Error: number ~> string
// Error: number ~> string
// This tests that, for node, the first name mapping that both matches *and*
// results in a valid module filename is picked.
// Error: number ~> string
// Error: number ~> string
// node_modules/Exists/index.js
// Error: number ~> string
// Error: number ~> string
var m1 = require(\"./1DoesntExist\"); var m1 = require(\"./1DoesntExist\");
var a_1: number = m1.numVal; var a_1: number = m1.numVal;
var a_2: string = m1.numVal; var a_2: string = m1.numVal;
// Error: number ~> string
import {numVal} from \"./1DoesntExist\"; import {numVal} from \"./1DoesntExist\";
var a_3: number = numVal; var a_3: number = numVal;
var a_4: string = numVal; var a_4: string = numVal;
// Error: number ~> string
// This tests that, for node, the first name mapping that both matches *and*
// results in a valid module filename is picked.
var m2 = require(\"./2DoesntExist\"); var m2 = require(\"./2DoesntExist\");
var b_1: number = m2.numVal; var b_1: number = m2.numVal;
var b_2: string = m2.numVal; var b_2: string = m2.numVal;
// Error: number ~> string
import {numVal as numVal2} from \"./3DoesntExist\"; import {numVal as numVal2} from \"./3DoesntExist\";
var b_3: number = numVal2; var b_3: number = numVal2;
var b_4: string = numVal2; var b_4: string = numVal2;
// Error: number ~> string
// node_modules/Exists/index.js
var m3 = require(\"4DoesntExist\"); var m3 = require(\"4DoesntExist\");
var c_1: number = m3.numVal; var c_1: number = m3.numVal;
var c_2: string = m3.numVal; var c_2: string = m3.numVal;
// Error: number ~> string
import {numVal as numVal3} from \"5DoesntExist\"; import {numVal as numVal3} from \"5DoesntExist\";
var c_3: number = numVal3; var c_3: number = numVal3;
var c_4: string = numVal3; var c_4: string = numVal3; // Error: number ~> string"
"
`; `;
exports[`test Exists.js 1`] = ` exports[`test Exists.js 1`] = `
@ -64,6 +63,6 @@ module.exports = {
}; };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
module.exports = { numVal: 42 };
" module.exports = { numVal: 42 };"
`; `;

View File

@ -7,9 +7,9 @@ import {name} from \"testproj\";
(name: \"custom_resolve_dir/testproj\"); // Error: Resolve from node_modules first! (name: \"custom_resolve_dir/testproj\"); // Error: Resolve from node_modules first!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// Error: Resolve from node_modules first!
import {name} from \"testproj\"; import {name} from \"testproj\";
(name: \"node_modules/testproj\"); (name: \"node_modules/testproj\");
(name: \"custom_resolve_dir/testproj\"); (name: \"custom_resolve_dir/testproj\"); // Error: Resolve from node_modules first!"
"
`; `;

View File

@ -4,6 +4,6 @@ exports[`test index.js 1`] = `
export var name: \"otherdir/testproj\" = \"otherdir/testproj\"; export var name: \"otherdir/testproj\" = \"otherdir/testproj\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
export var name: \"otherdir/testproj\" = \"otherdir/testproj\";
" export var name: \"otherdir/testproj\" = \"otherdir/testproj\";"
`; `;

View File

@ -4,6 +4,6 @@ exports[`test index.js 1`] = `
export var name: \"otherdir/testproj2\" = \"otherdir/testproj2\"; export var name: \"otherdir/testproj2\" = \"otherdir/testproj2\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
export var name: \"otherdir/testproj2\" = \"otherdir/testproj2\";
" export var name: \"otherdir/testproj2\" = \"otherdir/testproj2\";"
`; `;

View File

@ -7,9 +7,10 @@ import {name} from \"testproj2\";
(name: \"subdir/custom_resolve_dir/testproj2\"); (name: \"subdir/custom_resolve_dir/testproj2\");
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// Error: Resolve from sibling \'custom_resolve_dir\' first!
import {name} from \"testproj2\"; import {name} from \"testproj2\";
(name: \"node_modules/testproj2\"); (name: \"node_modules/testproj2\");
(name: \"subdir/custom_resolve_dir/testproj2\"); // Error: Resolve from sibling \'custom_resolve_dir\' first!
" (name: \"subdir/custom_resolve_dir/testproj2\");"
`; `;

View File

@ -4,6 +4,6 @@ exports[`test index.js 1`] = `
export var name: \"subdir/custom_resolve_dir/testproj2\" = \"subdir/custom_resolve_dir/testproj2\"; export var name: \"subdir/custom_resolve_dir/testproj2\" = \"subdir/custom_resolve_dir/testproj2\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
export var name: \"subdir/custom_resolve_dir/testproj2\" = \"subdir/custom_resolve_dir/testproj2\";
" export var name: \"subdir/custom_resolve_dir/testproj2\" = \"subdir/custom_resolve_dir/testproj2\";"
`; `;

View File

@ -35,9 +35,11 @@ class B extends A {
B._sProperty = \"B._sProperty string\"; B._sProperty = \"B._sProperty string\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
class A { class A {
_property1: number; _property1: number;
static _sProperty: number; static _sProperty: number;
constructor() { constructor() {
this._property1 = 5; this._property1 = 5;
} }
@ -49,9 +51,11 @@ class A {
} }
} }
A._sProperty = 48; A._sProperty = 48;
class B extends A { class B extends A {
_property1: string; _property1: string;
static _sProperty: string; static _sProperty: string;
constructor() { constructor() {
super(); super();
this._property1 = \"another string\"; this._property1 = \"another string\";
@ -63,8 +67,7 @@ class B extends A {
return 23; return 23;
} }
} }
B._sProperty = \"B._sProperty string\"; B._sProperty = \"B._sProperty string\";"
"
`; `;
exports[`test commonjs_export.js 1`] = ` exports[`test commonjs_export.js 1`] = `
@ -77,11 +80,12 @@ class C {
module.exports = new C; module.exports = new C;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
class C { class C {
_p: string; _p: string;
} }
module.exports = new C();
" module.exports = new C();"
`; `;
exports[`test commonjs_import.js 1`] = ` exports[`test commonjs_import.js 1`] = `
@ -90,6 +94,6 @@ exports[`test commonjs_import.js 1`] = `
import {_p} from \"./commonjs_export\"; import {_p} from \"./commonjs_export\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
import {_p} from \"./commonjs_export\";
" import {_p} from \"./commonjs_export\";"
`; `;

View File

@ -35,9 +35,11 @@ class B extends A {
B._sProperty = \"B._sProperty string\"; B._sProperty = \"B._sProperty string\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
class A { class A {
_property1: number; _property1: number;
static _sProperty: number; static _sProperty: number;
constructor() { constructor() {
this._property1 = 5; this._property1 = 5;
} }
@ -49,9 +51,11 @@ class A {
} }
} }
A._sProperty = 48; A._sProperty = 48;
class B extends A { class B extends A {
_property1: string; _property1: string;
static _sProperty: string; static _sProperty: string;
constructor() { constructor() {
super(); super();
this._property1 = \"another string\"; this._property1 = \"another string\";
@ -63,6 +67,5 @@ class B extends A {
return 23; return 23;
} }
} }
B._sProperty = \"B._sProperty string\"; B._sProperty = \"B._sProperty string\";"
"
`; `;

View File

@ -43,21 +43,21 @@ function durable_refi(x: ?number) {
* *
* @flow * @flow
*/ */
// error, const param cannot be reassigned
function cannot_reassign(x: string) {
x = \"hey\"; // error, const param cannot be reassigned
}
// Note: const params use the same machinery as explicit // Note: const params use the same machinery as explicit
// const bindings, which are tested more extensively elsewhere. // const bindings, which are tested more extensively elsewhere.
// Here we\'re just making sure the machinery is hooked up. // Here we\'re just making sure the machinery is hooked up.
// //
// ok: if x is truthy here, it\'s truthy everywhere
function cannot_reassign(x: string) {
x = \"hey\";
}
function durable_refi(x: ?number) { function durable_refi(x: ?number) {
if (x) { if (x) {
// ok: if x is truthy here, it\'s truthy everywhere
return () => { return () => {
var y: number = x; var y: number = x;
}; };
} }
} }"
"
`; `;

View File

@ -12,9 +12,10 @@ module.exports = C;
class C { class C {
constructor() {} constructor() {}
} }
class D { class D {
constructor(): number {} constructor(): number {}
} }
module.exports = C;
" module.exports = C;"
`; `;

View File

@ -22,31 +22,30 @@ interface IFoo extends IFooPrototype {
exports.Foo2 = (Foo: Class<IFoo>); exports.Foo2 = (Foo: Class<IFoo>);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Foo is a class-like function // Foo is a class-like function
// constructs objects with property x
// has static property y
// exporting Foo directly doesn\'t work
// Foo\'s instance and static props are not picked up
// so you want to type Foo, by declaring it as a class
/* error, should have declared x: number instead*/
/* error, should have declared static y: number instead*/
function Foo() { function Foo() {
this.x = 0; this.x = 0; // constructs objects with property x
} }
Foo.y = 0; Foo.y = 0;
// has static property y
Foo.prototype = { Foo.prototype = {
m() { m() {
return 0; return 0;
} }
}; };
// exporting Foo directly doesn\'t work
// Foo\'s instance and static props are not picked up
exports.Foo = Foo; exports.Foo = Foo;
// so you want to type Foo, by declaring it as a class
interface IFooPrototype { m(): number } interface IFooPrototype { m(): number }
interface IFoo extends IFooPrototype { interface IFoo extends IFooPrototype {
/* error, should have declared x: number instead*/
static (): void, static (): void,
x: boolean, x: boolean,
static y: boolean static y: boolean /* error, should have declared static y: number instead*/
} }
exports.Foo2 = (Foo: Class<IFoo>); exports.Foo2 = (Foo: Class<IFoo>);"
"
`; `;
exports[`test test.js 1`] = ` exports[`test test.js 1`] = `
@ -60,17 +59,17 @@ var x2: string = new Foo2().x; // error, found boolean instead of string
var y2: string = Foo2.y; // error, found boolean instead of string var y2: string = Foo2.y; // error, found boolean instead of string
var z2: string = new Foo2().m(); var z2: string = new Foo2().m();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, found number instead of string
// error, found number instead of string
// error, found boolean instead of string
// error, found boolean instead of string
var Foo = require(\"./constructors\").Foo; var Foo = require(\"./constructors\").Foo;
var x: string = new Foo().x; var x: string = new Foo().x;
// error, found number instead of string
var y: string = Foo.y; var y: string = Foo.y;
// error, found number instead of string
var z: string = new Foo().m(); var z: string = new Foo().m();
var Foo2 = require(\"./constructors\").Foo2; var Foo2 = require(\"./constructors\").Foo2;
var x2: string = new Foo2().x; var x2: string = new Foo2().x;
// error, found boolean instead of string
var y2: string = Foo2.y; var y2: string = Foo2.y;
var z2: string = new Foo2().m(); // error, found boolean instead of string
" var z2: string = new Foo2().m();"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test dummy.js 1`] = ` exports[`test dummy.js 1`] = `
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
" "
`; `;
@ -11,6 +10,5 @@ xxx
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./dummy\"); require(\"./dummy\");
var xxx = 0; var xxx = 0;
xxx; xxx;"
"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test dummy.js 1`] = ` exports[`test dummy.js 1`] = `
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
" "
`; `;
@ -11,6 +10,5 @@ xxx
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./dummy\"); require(\"./dummy\");
var xxx = 0; var xxx = 0;
xxx; xxx;"
"
`; `;

View File

@ -43,12 +43,11 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// Boolean (the class) tests. booleans (the literals) are not part of core.js // Boolean (the class) tests. booleans (the literals) are not part of core.js
// constructor
// toString
// valueOf
// casting
let tests = [ let tests = [
// constructor
function() { function() {
new Boolean(); new Boolean();
new Boolean(0); new Boolean(0);
@ -59,15 +58,18 @@ let tests = [
new Boolean(undefined); new Boolean(undefined);
new Boolean(\"\"); new Boolean(\"\");
}, },
// toString
function() { function() {
true.toString(); true.toString();
let x: boolean = false; let x: boolean = false;
x.toString(); x.toString();
new Boolean(true).toString(); new Boolean(true).toString();
}, },
// valueOf
function() { function() {
(new Boolean(0).valueOf(): boolean); (new Boolean(0).valueOf(): boolean);
}, },
// casting
function() { function() {
Boolean(); Boolean();
Boolean(0); Boolean(0);
@ -78,8 +80,7 @@ let tests = [
Boolean(undefined); Boolean(undefined);
Boolean(\"\"); Boolean(\"\");
} }
]; ];"
"
`; `;
exports[`test map.js 1`] = ` exports[`test map.js 1`] = `
@ -117,19 +118,15 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// good constructors
// bad constructors
// error
// error
// get()
// error, string | void
// error, wrong key type
function* generator(): Iterable<[string, number]> { function* generator(): Iterable<[string, number]> {
while (true) { while (true) {
yield [ \"foo\", 123 ]; yield [ \"foo\", 123 ];
} }
} }
let tests = [ let tests = [
// good constructors
function() { function() {
let w = new Map(); let w = new Map();
let x = new Map(null); let x = new Map(null);
@ -139,16 +136,19 @@ let tests = [
let b: Map<string, number> = new Map([ [ \"foo\", 123 ] ]); let b: Map<string, number> = new Map([ [ \"foo\", 123 ] ]);
let c: Map<string, number> = new Map(generator()); let c: Map<string, number> = new Map(generator());
}, },
// bad constructors
function() { function() {
let x = new Map([ \"foo\", 123 ]); let x = new Map([ \"foo\", 123 ]);
let y: Map<number, string> = new Map([ [ \"foo\", 123 ] ]); // error
let y: Map<number, string> = new Map([ [ \"foo\", 123 ] ]); // error
}, },
// get()
function(x: Map<string, number>) { function(x: Map<string, number>) {
(x.get(\"foo\"): boolean); (x.get(\"foo\"): boolean);
x.get(123); // error, string | void
x.get(123); // error, wrong key type
} }
]; ];"
"
`; `;
exports[`test regexp.js 1`] = ` exports[`test regexp.js 1`] = `
@ -183,38 +183,35 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// constructor
// invalid in ES5, valid in ES6
// invalid in ES5, valid in ES6
// called as a function (equivalent to the constructor per ES6 21.2.3)
// invalid in ES5, valid in ES6
// invalid in ES5, valid in ES6
// invalid flags
// error
// error
let tests = [ let tests = [
// constructor
function() { function() {
new RegExp(\"foo\"); new RegExp(\"foo\");
new RegExp(/foo/); new RegExp(/foo/);
new RegExp(\"foo\", \"i\"); new RegExp(\"foo\", \"i\");
new RegExp(\"foo\", \"ig\"); new RegExp(\"foo\", \"ig\");
new RegExp(/foo/, \"i\"); new RegExp(/foo/, \"i\");
new RegExp(/foo/g, \"i\"); // invalid in ES5, valid in ES6
new RegExp(/foo/g, \"i\"); // invalid in ES5, valid in ES6
}, },
// called as a function (equivalent to the constructor per ES6 21.2.3)
function() { function() {
RegExp(\"foo\"); RegExp(\"foo\");
RegExp(/foo/); RegExp(/foo/);
RegExp(\"foo\", \"i\"); RegExp(\"foo\", \"i\");
RegExp(\"foo\", \"ig\"); RegExp(\"foo\", \"ig\");
RegExp(/foo/, \"i\"); RegExp(/foo/, \"i\");
RegExp(/foo/g, \"i\"); // invalid in ES5, valid in ES6
RegExp(/foo/g, \"i\"); // invalid in ES5, valid in ES6
}, },
// invalid flags
function() { function() {
RegExp(\"foo\", \"z\"); RegExp(\"foo\", \"z\");
new RegExp(\"foo\", \"z\"); // error
new RegExp(\"foo\", \"z\"); // error
} }
]; ];"
"
`; `;
exports[`test weakset.js 1`] = ` exports[`test weakset.js 1`] = `
@ -256,11 +253,11 @@ function* numbers(): Iterable<number> {
let ws5 = new WeakSet(numbers()); // error, must be objects let ws5 = new WeakSet(numbers()); // error, must be objects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// error, must be objects
// error, must be objects
let ws = new WeakSet(); let ws = new WeakSet();
let obj: Object = {}; let obj: Object = {};
let dict: { foo: string } = { foo: \"bar\" }; let dict: { foo: string } = { foo: \"bar\" };
ws.add(window); ws.add(window);
ws.add(obj); ws.add(obj);
ws.add(dict); ws.add(dict);
@ -270,20 +267,25 @@ ws.has(dict);
ws.delete(window); ws.delete(window);
ws.delete(obj); ws.delete(obj);
ws.delete(dict); ws.delete(dict);
let ws2 = new WeakSet([ obj, dict ]); let ws2 = new WeakSet([ obj, dict ]);
let ws3 = new WeakSet([ 1, 2, 3 ]); let ws3 = new WeakSet([ 1, 2, 3 ]);
// error, must be objects
function* generator(): Iterable<{ foo: string }> { function* generator(): Iterable<{ foo: string }> {
while (true) { while (true) {
yield { foo: \"bar\" }; yield { foo: \"bar\" };
} }
} }
let ws4 = new WeakSet(generator()); let ws4 = new WeakSet(generator());
function* numbers(): Iterable<number> { function* numbers(): Iterable<number> {
let i = 0; let i = 0;
while (true) { while (true) {
yield i++; yield i++;
} }
} }
let ws5 = new WeakSet(numbers());
" let ws5 = new WeakSet(numbers()); // error, must be objects"
`; `;

View File

@ -49,9 +49,23 @@ n.x = [0];
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
type CovArrayVerbose<X, Y: X> = Array<Y>;
var b: CovArrayVerbose<number, *> = [];
var y: CovArrayVerbose<mixed, *> = b;
y[0] = \"\";
// error // error
class NVerbose<E, I: E> {
x: CovArrayVerbose<E, I>;
foo(): CovArrayVerbose<mixed, I> {
return this.x;
}
}
var nv: NVerbose<number, *> = new NVerbose();
nv.x = [ 0 ];
(nv.x[0]: string);
// error // error
// error (nv.foo()[0]: string); // error
/* TODO: use existentials for non-verbose covariance? /* TODO: use existentials for non-verbose covariance?
type CovArray<X> = Array<*:X>; type CovArray<X> = Array<*:X>;
@ -85,20 +99,5 @@ n.x = [0];
(n.x[0]: string); // error (n.x[0]: string); // error
(n.foo()[0]: string); // not an error! (n.foo()[0]: string); // not an error!
*/ */"
type CovArrayVerbose<X, Y: X> = Array<Y>;
var b: CovArrayVerbose<number, *> = [];
var y: CovArrayVerbose<mixed, *> = b;
y[0] = \"\";
class NVerbose<E, I: E> {
x: CovArrayVerbose<E, I>;
foo(): CovArrayVerbose<mixed, I> {
return this.x;
}
}
var nv: NVerbose<number, *> = new NVerbose();
nv.x = [ 0 ];
(nv.x[0]: string);
(nv.foo()[0]: string);
"
`; `;

View File

@ -11,13 +11,12 @@ declare module bar {
// TODO // TODO
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
declare module foo {}
// TODO
// This file triggers a violation of the \"disjoint-or-nested ranges invariant\" // This file triggers a violation of the \"disjoint-or-nested ranges invariant\"
// that we implicitly assume in type-at-pos and coverage implementations. In // that we implicitly assume in type-at-pos and coverage implementations. In
// particular, when unchecked it causes a crash with coverage --color. // particular, when unchecked it causes a crash with coverage --color.
// TODO declare module bar {}"
declare module foo {}
declare module bar {}
"
`; `;
exports[`test declare_module.js 1`] = ` exports[`test declare_module.js 1`] = `
@ -27,8 +26,8 @@ declare module foo {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// check coverage of declare module // check coverage of declare module
declare module foo {}
" declare module foo {}"
`; `;
exports[`test no_pragma.js 1`] = ` exports[`test no_pragma.js 1`] = `
@ -36,8 +35,7 @@ exports[`test no_pragma.js 1`] = `
(x: string); (x: string);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let x = 0; let x = 0;
(x: string); (x: string);"
"
`; `;
exports[`test non-termination.js 1`] = ` exports[`test non-termination.js 1`] = `
@ -56,12 +54,11 @@ declare module bar {
declare class qux { declare class qux {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
declare module foo {}
// This file triggers a violation of the \"disjoint-or-nested ranges invariant\" // This file triggers a violation of the \"disjoint-or-nested ranges invariant\"
// that we implicitly assume in type-at-pos and coverage implementations. In // that we implicitly assume in type-at-pos and coverage implementations. In
// particular, when unchecked it causes non-termination with coverage --color. // particular, when unchecked it causes non-termination with coverage --color.
// TODO
declare module foo {}
declare module bar {} declare module bar {}
declare class qux {} // TODO
" declare class qux {}"
`; `;

View File

@ -6,9 +6,10 @@ class A extends B { }
module.exports = A; module.exports = A;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var B = require(\"./B\"); var B = require(\"./B\");
class A extends B {} class A extends B {}
module.exports = A;
" module.exports = A;"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
@ -18,8 +19,8 @@ exports[`test B.js 1`] = `
module.exports = B; module.exports = B;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//class B extends A { }
var A = require(\"./A\"); var A = require(\"./A\");
module.exports = B;
" //class B extends A { }
module.exports = B;"
`; `;

View File

@ -28,12 +28,12 @@ new Date(2015, 6, 18, 11, 55, 42, \'999\');
new Date(\'2015\', 6); new Date(\'2015\', 6);
new Date(2015, 6, 18, 11, 55, 42, 999, \'hahaha\'); new Date(2015, 6, 18, 11, 55, 42, 999, \'hahaha\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// valid constructors
// invalid constructors
// invalid constructors that we incorrectly consider valid
var d = new Date(0); var d = new Date(0);
var x: string = d.getTime(); var x: string = d.getTime();
var y: number = d; var y: number = d;
// valid constructors
new Date(); new Date();
new Date(1234567890); new Date(1234567890);
new Date(\"2015/06/18\"); new Date(\"2015/06/18\");
@ -43,6 +43,8 @@ new Date(2015, 6, 18, 11);
new Date(2015, 6, 18, 11, 55); new Date(2015, 6, 18, 11, 55);
new Date(2015, 6, 18, 11, 55, 42); new Date(2015, 6, 18, 11, 55, 42);
new Date(2015, 6, 18, 11, 55, 42, 999); new Date(2015, 6, 18, 11, 55, 42, 999);
// invalid constructors
new Date({}); new Date({});
new Date(2015, \"6\"); new Date(2015, \"6\");
new Date(2015, 6, \"18\"); new Date(2015, 6, \"18\");
@ -50,7 +52,8 @@ new Date(2015, 6, 18, \"11\");
new Date(2015, 6, 18, 11, \"55\"); new Date(2015, 6, 18, 11, \"55\");
new Date(2015, 6, 18, 11, 55, \"42\"); new Date(2015, 6, 18, 11, 55, \"42\");
new Date(2015, 6, 18, 11, 55, 42, \"999\"); new Date(2015, 6, 18, 11, 55, 42, \"999\");
// invalid constructors that we incorrectly consider valid
new Date(\"2015\", 6); new Date(\"2015\", 6);
new Date(2015, 6, 18, 11, 55, 42, 999, \"hahaha\"); new Date(2015, 6, 18, 11, 55, 42, 999, \"hahaha\");"
"
`; `;

View File

@ -10,8 +10,8 @@ module.exports.fun = (): string => \"hello there\";
* @providesModule ExplicitProvidesModuleDifferentName * @providesModule ExplicitProvidesModuleDifferentName
* @flow * @flow
*/ */
module.exports.fun = (): string => \"hello there\";
" module.exports.fun = (): string => \"hello there\";"
`; `;
exports[`test ExplicitProvidesModuleSameName.js 1`] = ` exports[`test ExplicitProvidesModuleSameName.js 1`] = `
@ -26,8 +26,8 @@ module.exports.fun = (): string => \"hello there\";
* @providesModule ExplicitProvidesModuleSameName * @providesModule ExplicitProvidesModuleSameName
* @flow * @flow
*/ */
module.exports.fun = (): string => \"hello there\";
" module.exports.fun = (): string => \"hello there\";"
`; `;
exports[`test ImplicitProvidesModule.js 1`] = ` exports[`test ImplicitProvidesModule.js 1`] = `
@ -42,15 +42,13 @@ module.exports.fun = (): string => \"hello there\";
* @providesModule ImplicitProvidesModule * @providesModule ImplicitProvidesModule
* @flow * @flow
*/ */
module.exports.fun = (): string => \"hello there\";
" module.exports.fun = (): string => \"hello there\";"
`; `;
exports[`test md5.js 1`] = ` exports[`test md5.js 1`] = `
"/* @providesModule md5 */ "/* @providesModule md5 */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @providesModule md5 */
" "
`; `;
@ -67,11 +65,13 @@ var ExplicitDifferentName = require(\'ExplicitProvidesModuleDifferentName\');
(ExplicitDifferentName.fun(): string); (ExplicitDifferentName.fun(): string);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
var Implicit = require(\"ImplicitProvidesModule\"); var Implicit = require(\"ImplicitProvidesModule\");
(Implicit.fun(): string); (Implicit.fun(): string);
var ExplicitSameName = require(\"ExplicitProvidesModuleSameName\"); var ExplicitSameName = require(\"ExplicitProvidesModuleSameName\");
(ExplicitSameName.fun(): string); (ExplicitSameName.fun(): string);
var ExplicitDifferentName = require(\"ExplicitProvidesModuleDifferentName\"); var ExplicitDifferentName = require(\"ExplicitProvidesModuleDifferentName\");
(ExplicitDifferentName.fun(): string); (ExplicitDifferentName.fun(): string);"
"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test min.js 1`] = ` exports[`test min.js 1`] = `
"module.exports.fun = (): string => \"hello there\"; "module.exports.fun = (): string => \"hello there\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
module.exports.fun = (): string => \"hello there\"; module.exports.fun = (): string => \"hello there\";"
"
`; `;

View File

@ -14,14 +14,16 @@ var unreachable = require(\'annotation\');
(corge.fun(): string); (corge.fun(): string);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// make sure we don\'t pick up non-header @providesModule
// annotations - see node_modules/qux/docblock.js
var docblock = require(\"qux/docblock\"); var docblock = require(\"qux/docblock\");
var min = require(\"d3/min.js\"); var min = require(\"d3/min.js\");
var corge = require(\"qux/corge\"); var corge = require(\"qux/corge\");
// make sure we don\'t pick up non-header @providesModule
// annotations - see node_modules/qux/docblock.js
var unreachable = require(\"annotation\"); var unreachable = require(\"annotation\");
(docblock.fun(): string); (docblock.fun(): string);
(min.fun(): string); (min.fun(): string);
(corge.fun(): string); (corge.fun(): string);"
"
`; `;

View File

@ -1,5 +1,4 @@
exports[`test index.js 1`] = ` exports[`test index.js 1`] = `
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
" "
`; `;

View File

@ -1,6 +1,5 @@
exports[`test client.js 1`] = ` exports[`test client.js 1`] = `
"var ws = require(\'../\'); "var ws = require(\'../\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var ws = require(\"../\"); var ws = require(\"../\");"
"
`; `;

View File

@ -7,8 +7,7 @@ export function foo(): Implementation { return new Implementation; }
class Implementation {} class Implementation {}
export function foo(): Implementation { export function foo(): Implementation {
return new Implementation(); return new Implementation();
} }"
"
`; `;
exports[`test ExplicitProvidesModuleDifferentName.js 1`] = ` exports[`test ExplicitProvidesModuleDifferentName.js 1`] = `
@ -24,9 +23,9 @@ module.exports.fun = (): Implementation => new Implementation;
* @providesModule ExplicitProvidesModuleDifferentName * @providesModule ExplicitProvidesModuleDifferentName
* @flow * @flow
*/ */
class Implementation {} class Implementation {}
module.exports.fun = (): Implementation => new Implementation(); module.exports.fun = (): Implementation => new Implementation();"
"
`; `;
exports[`test ExplicitProvidesModuleSameName.js 1`] = ` exports[`test ExplicitProvidesModuleSameName.js 1`] = `
@ -42,9 +41,9 @@ module.exports.fun = (): Implementation => new Implementation;
* @providesModule ExplicitProvidesModuleSameName * @providesModule ExplicitProvidesModuleSameName
* @flow * @flow
*/ */
class Implementation {} class Implementation {}
module.exports.fun = (): Implementation => new Implementation(); module.exports.fun = (): Implementation => new Implementation();"
"
`; `;
exports[`test ImplicitProvidesModule.js 1`] = ` exports[`test ImplicitProvidesModule.js 1`] = `
@ -60,16 +59,14 @@ module.exports.fun = (): Implementation => new Implementation;
* @providesModule ImplicitProvidesModule * @providesModule ImplicitProvidesModule
* @flow * @flow
*/ */
class Implementation {} class Implementation {}
module.exports.fun = (): Implementation => new Implementation(); module.exports.fun = (): Implementation => new Implementation();"
"
`; `;
exports[`test md5.js 1`] = ` exports[`test md5.js 1`] = `
"/* @providesModule md5 */ "/* @providesModule md5 */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @providesModule md5 */
" "
`; `;
@ -86,14 +83,13 @@ var ExplicitDifferentName = require(\'ExplicitProvidesModuleDifferentName\');
(ExplicitDifferentName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean (ExplicitDifferentName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Error: Either Implementation ~> boolean or Declaration ~> boolean
// Error: Either Implementation ~> boolean or Declaration ~> boolean
// Error: Either Implementation ~> boolean or Declaration ~> boolean
var Implicit = require(\"ImplicitProvidesModule\"); var Implicit = require(\"ImplicitProvidesModule\");
(Implicit.fun(): boolean); (Implicit.fun(): boolean);
// Error: Either Implementation ~> boolean or Declaration ~> boolean
var ExplicitSameName = require(\"ExplicitProvidesModuleSameName\"); var ExplicitSameName = require(\"ExplicitProvidesModuleSameName\");
(ExplicitSameName.fun(): boolean); (ExplicitSameName.fun(): boolean);
// Error: Either Implementation ~> boolean or Declaration ~> boolean
var ExplicitDifferentName = require(\"ExplicitProvidesModuleDifferentName\"); var ExplicitDifferentName = require(\"ExplicitProvidesModuleDifferentName\");
(ExplicitDifferentName.fun(): boolean); (ExplicitDifferentName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean"
"
`; `;

View File

@ -3,6 +3,5 @@ exports[`test min.js 1`] = `
module.exports.fun = (): Implementation => new Implementation; module.exports.fun = (): Implementation => new Implementation;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Implementation {} class Implementation {}
module.exports.fun = (): Implementation => new Implementation(); module.exports.fun = (): Implementation => new Implementation();"
"
`; `;

View File

@ -10,14 +10,14 @@ var corge = require(\'qux/corge\');
(corge.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean (corge.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// Error: Either Implementation ~> boolean or Declaration ~> boolean
// Error: Either Implementation ~> boolean or Declaration ~> boolean
// Error: Either Implementation ~> boolean or Declaration ~> boolean
var docblock = require(\"qux/docblock\"); var docblock = require(\"qux/docblock\");
var min = require(\"d3/min.js\"); var min = require(\"d3/min.js\");
var corge = require(\"qux/corge\"); var corge = require(\"qux/corge\");
(docblock.fun(): boolean); (docblock.fun(): boolean);
// Error: Either Implementation ~> boolean or Declaration ~> boolean
(min.fun(): boolean); (min.fun(): boolean);
(corge.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean
" (corge.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean"
`; `;

View File

@ -1,5 +1,4 @@
exports[`test index.js 1`] = ` exports[`test index.js 1`] = `
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
" "
`; `;

View File

@ -1,6 +1,5 @@
exports[`test client.js 1`] = ` exports[`test client.js 1`] = `
"var ws = require(\'../\'); "var ws = require(\'../\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var ws = require(\"../\"); var ws = require(\"../\");"
"
`; `;

View File

@ -5,8 +5,7 @@ export function foo(): Implementation { return new Implementation; }
class Implementation {} class Implementation {}
export function foo(): Implementation { export function foo(): Implementation {
return new Implementation(); return new Implementation();
} }"
"
`; `;
exports[`test test_absolute.js 1`] = ` exports[`test test_absolute.js 1`] = `
@ -53,47 +52,46 @@ var F = require(\'package_with_dir_main\');
(F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean (F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// This will require ./node_modules/B.js.flow // This will require ./node_modules/B.js.flow
// Error either Implementation ~> boolean or Declaration ~> boolean
// This will require ./node_modules/B.js.flow
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// This will require ./node_modules/B.js.flow
// Error either Implementation ~> boolean or Declaration ~> boolean
// This will require ./node_modules/B.js.flow
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
// Error either Implementation ~> boolean or Declaration ~> boolean
var B1 = require(\"B\"); var B1 = require(\"B\");
(B1.fun(): boolean); (B1.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
// This will require ./node_modules/B.js.flow
var B2 = require(\"B.js\"); var B2 = require(\"B.js\");
(B2.fun(): boolean); (B2.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var C = require(\"package_with_full_main\"); var C = require(\"package_with_full_main\");
(C.fun(): boolean); (C.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var D = require(\"package_with_partial_main\"); var D = require(\"package_with_partial_main\");
(D.fun(): boolean); (D.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var E = require(\"package_with_no_package_json\"); var E = require(\"package_with_no_package_json\");
(E.fun(): boolean); (E.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var F = require(\"package_with_dir_main\"); var F = require(\"package_with_dir_main\");
(F.fun(): boolean); (F.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
// This will require ./node_modules/B.js.flow
var B1 = require(\"B\"); var B1 = require(\"B\");
(B1.fun(): boolean); (B1.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
// This will require ./node_modules/B.js.flow
var B2 = require(\"B.js\"); var B2 = require(\"B.js\");
(B2.fun(): boolean); (B2.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var C = require(\"package_with_full_main\"); var C = require(\"package_with_full_main\");
(C.fun(): boolean); (C.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var D = require(\"package_with_partial_main\"); var D = require(\"package_with_partial_main\");
(D.fun(): boolean); (D.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var E = require(\"package_with_no_package_json\"); var E = require(\"package_with_no_package_json\");
(E.fun(): boolean); (E.fun(): boolean);
// Error either Implementation ~> boolean or Declaration ~> boolean
var F = require(\"package_with_dir_main\"); var F = require(\"package_with_dir_main\");
(F.fun(): boolean); (F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean"
"
`; `;
exports[`test test_relative.js 1`] = ` exports[`test test_relative.js 1`] = `
@ -101,8 +99,7 @@ exports[`test test_relative.js 1`] = `
(foo(): boolean); // Error: either Implementation ~> boolean or Definition ~> boolean (foo(): boolean); // Error: either Implementation ~> boolean or Definition ~> boolean
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Error: either Implementation ~> boolean or Definition ~> boolean
import {foo} from \"./A\"; import {foo} from \"./A\";
(foo(): boolean);
" (foo(): boolean); // Error: either Implementation ~> boolean or Definition ~> boolean"
`; `;

View File

@ -4,8 +4,8 @@ exports[`test A.js 1`] = `
module.exports.fun = (): string => \'hello there!\'; module.exports.fun = (): string => \'hello there!\';
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
module.exports.fun = (): string => \"hello there!\";
" module.exports.fun = (): string => \"hello there!\";"
`; `;
exports[`test CJS.js 1`] = ` exports[`test CJS.js 1`] = `
@ -13,8 +13,7 @@ exports[`test CJS.js 1`] = `
module.exports = 42; module.exports = 42;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
module.exports = 42; module.exports = 42;"
"
`; `;
exports[`test test_absolute.js 1`] = ` exports[`test test_absolute.js 1`] = `
@ -41,27 +40,26 @@ var F = require(\'package_with_dir_main\');
(F.fun(): string); // Error number ~> string (F.fun(): string); // Error number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// This will require ./node_modules/B.js.flow // This will require ./node_modules/B.js.flow
// Error number ~> string
// This will require ./node_modules/B.js.flow
// Error number ~> string
// Error number ~> string
// Error number ~> string
// Error number ~> string
// Error number ~> string
var B1 = require(\"B\"); var B1 = require(\"B\");
(B1.fun(): string); (B1.fun(): string);
// Error number ~> string
// This will require ./node_modules/B.js.flow
var B2 = require(\"B.js\"); var B2 = require(\"B.js\");
(B2.fun(): string); (B2.fun(): string);
// Error number ~> string
var C = require(\"package_with_full_main\"); var C = require(\"package_with_full_main\");
(C.fun(): string); (C.fun(): string);
// Error number ~> string
var D = require(\"package_with_partial_main\"); var D = require(\"package_with_partial_main\");
(D.fun(): string); (D.fun(): string);
// Error number ~> string
var E = require(\"package_with_no_package_json\"); var E = require(\"package_with_no_package_json\");
(E.fun(): string); (E.fun(): string);
// Error number ~> string
var F = require(\"package_with_dir_main\"); var F = require(\"package_with_dir_main\");
(F.fun(): string); (F.fun(): string); // Error number ~> string"
"
`; `;
exports[`test test_relative.js 1`] = ` exports[`test test_relative.js 1`] = `
@ -80,17 +78,16 @@ var CJS = require(\'./CJS.js\');
(CJS: number); // Error: string ~> number (CJS: number); // Error: string ~> number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// This will require ./A.js.flow // This will require ./A.js.flow
// Error number ~> string
// This will require ./A.js.flow
// Error number ~> string
// Error: string ~> number
var A1 = require(\"./A\"); var A1 = require(\"./A\");
(A1.fun(): string); (A1.fun(): string);
// Error number ~> string
// This will require ./A.js.flow
var A2 = require(\"./A.js\"); var A2 = require(\"./A.js\");
(A2.fun(): string); (A2.fun(): string);
// Error number ~> string
var CJS = require(\"./CJS.js\"); var CJS = require(\"./CJS.js\");
(CJS: string); (CJS: string);
(CJS: number); (CJS: number); // Error: string ~> number"
"
`; `;

View File

@ -10,11 +10,11 @@ C.foo(\"\");
(C.name: string); (C.name: string);
(C.name: number); // error, it\'s a string (C.name: number); // error, it\'s a string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, it\'s a string
declare class C { static x: number, static foo(x: number): void } declare class C { static x: number, static foo(x: number): void }
C.x = \"\"; C.x = \"\";
C.foo(\"\"); C.foo(\"\");
(C.name: string); (C.name: string);
(C.name: number); (C.name: number); // error, it\'s a string"
"
`; `;

View File

@ -11,6 +11,5 @@ declare class D extends _module.C {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
declare class _C { foo(): number } declare class _C { foo(): number }
declare var _module: { C: Class<_C> }; declare var _module: { C: Class<_C> };
declare class D extends _module.C { foo(): string } declare class D extends _module.C { foo(): string }"
"
`; `;

View File

@ -4,15 +4,13 @@ exports[`test B.js 1`] = `
exports.numberValue = 42; exports.numberValue = 42;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
exports.numberValue = 42;
" exports.numberValue = 42;"
`; `;
exports[`test C.js 1`] = ` exports[`test C.js 1`] = `
"/* @flow */ "/* @flow */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
" "
`; `;
@ -43,11 +41,14 @@ module.exports = Test;
* @providesModule CommonJS_Clobbering_Class * @providesModule CommonJS_Clobbering_Class
* @flow * @flow
*/ */
class Base { class Base {
static baseProp: number; static baseProp: number;
} }
class Test extends Base { class Test extends Base {
static childProp: number; static childProp: number;
static staticNumber1(): number { static staticNumber1(): number {
return 1; return 1;
} }
@ -57,6 +58,7 @@ class Test extends Base {
static staticNumber3(): number { static staticNumber3(): number {
return 3; return 3;
} }
instNumber1(): number { instNumber1(): number {
return 1; return 1;
} }
@ -64,8 +66,8 @@ class Test extends Base {
return 2; return 2;
} }
} }
module.exports = Test;
" module.exports = Test;"
`; `;
exports[`test CommonJS_Clobbering_Lit.js 1`] = ` exports[`test CommonJS_Clobbering_Lit.js 1`] = `
@ -86,14 +88,14 @@ module.exports = {
* @providesModule CommonJS_Clobbering_Lit * @providesModule CommonJS_Clobbering_Lit
* @flow * @flow
*/ */
module.exports = { module.exports = {
numberValue1: 1, numberValue1: 1,
numberValue2: 2, numberValue2: 2,
numberValue3: 3, numberValue3: 3,
numberValue4: 4, numberValue4: 4,
numberValue5: 5 numberValue5: 5
}; };"
"
`; `;
exports[`test CommonJS_Named.js 1`] = ` exports[`test CommonJS_Named.js 1`] = `
@ -112,12 +114,12 @@ exports.numberValue5 = 5;
* @providesModule CommonJS_Named * @providesModule CommonJS_Named
* @flow * @flow
*/ */
exports.numberValue1 = 1; exports.numberValue1 = 1;
exports.numberValue2 = 2; exports.numberValue2 = 2;
exports.numberValue3 = 3; exports.numberValue3 = 3;
exports.numberValue4 = 4; exports.numberValue4 = 4;
exports.numberValue5 = 5; exports.numberValue5 = 5;"
"
`; `;
exports[`test ES6_Default_AnonFunction1.js 1`] = ` exports[`test ES6_Default_AnonFunction1.js 1`] = `
@ -132,8 +134,8 @@ declare export default () => number;
* @providesModule ES6_Default_AnonFunction1 * @providesModule ES6_Default_AnonFunction1
* @flow * @flow
*/ */
declare export default () => number
" declare export default () => number"
`; `;
exports[`test ES6_Default_AnonFunction2.js 1`] = ` exports[`test ES6_Default_AnonFunction2.js 1`] = `
@ -148,8 +150,8 @@ declare export default () =>number;
* @providesModule ES6_Default_AnonFunction2 * @providesModule ES6_Default_AnonFunction2
* @flow * @flow
*/ */
declare export default () => number
" declare export default () => number"
`; `;
exports[`test ES6_Default_NamedClass1.js 1`] = ` exports[`test ES6_Default_NamedClass1.js 1`] = `
@ -170,13 +172,14 @@ declare export function getAFoo(): FooImpl;
* @providesModule ES6_Default_NamedClass1 * @providesModule ES6_Default_NamedClass1
* @flow * @flow
*/ */
declare export default class FooImpl { givesANum(): number }
// Regression test for https://github.com/facebook/flow/issues/511 // Regression test for https://github.com/facebook/flow/issues/511
// //
// Default-exported class should also be available in local scope // Default-exported class should also be available in local scope
declare export default class FooImpl { givesANum(): number }
declare export {FooImpl as Foo} declare export {FooImpl as Foo}
declare export function getAFoo(): FooImpl; declare export function getAFoo(): FooImpl;"
"
`; `;
exports[`test ES6_Default_NamedClass2.js 1`] = ` exports[`test ES6_Default_NamedClass2.js 1`] = `
@ -191,6 +194,7 @@ declare export default class Foo { givesANum(): number; };
* @providesModule ES6_Default_NamedClass2 * @providesModule ES6_Default_NamedClass2
* @flow * @flow
*/ */
declare export default class Foo { givesANum(): number } declare export default class Foo { givesANum(): number }
" "
`; `;
@ -207,8 +211,8 @@ declare export default function foo():number;
* @providesModule ES6_Default_NamedFunction1 * @providesModule ES6_Default_NamedFunction1
* @flow * @flow
*/ */
declare export default function foo(): number;
" declare export default function foo(): number;"
`; `;
exports[`test ES6_Default_NamedFunction2.js 1`] = ` exports[`test ES6_Default_NamedFunction2.js 1`] = `
@ -223,8 +227,8 @@ declare export default function foo():number;
* @providesModule ES6_Default_NamedFunction2 * @providesModule ES6_Default_NamedFunction2
* @flow * @flow
*/ */
declare export default function foo(): number;
" declare export default function foo(): number;"
`; `;
exports[`test ES6_DefaultAndNamed.js 1`] = ` exports[`test ES6_DefaultAndNamed.js 1`] = `
@ -234,9 +238,9 @@ declare export default number;
declare export var str: string; declare export var str: string;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
declare export default number declare export default number
declare export var str: string; declare export var str: string;"
"
`; `;
exports[`test ES6_ExportAllFrom_Intermediary1.js 1`] = ` exports[`test ES6_ExportAllFrom_Intermediary1.js 1`] = `
@ -251,8 +255,8 @@ declare export * from \"ES6_ExportAllFrom_Source1\";
* @providesModule ES6_ExportAllFrom_Intermediary1 * @providesModule ES6_ExportAllFrom_Intermediary1
* @flow * @flow
*/ */
declare export * from \"ES6_ExportAllFrom_Source1\"
" declare export * from \"ES6_ExportAllFrom_Source1\""
`; `;
exports[`test ES6_ExportAllFrom_Intermediary2.js 1`] = ` exports[`test ES6_ExportAllFrom_Intermediary2.js 1`] = `
@ -267,8 +271,8 @@ declare export * from \"ES6_ExportAllFrom_Source2\";
* @providesModule ES6_ExportAllFrom_Intermediary2 * @providesModule ES6_ExportAllFrom_Intermediary2
* @flow * @flow
*/ */
declare export * from \"ES6_ExportAllFrom_Source2\"
" declare export * from \"ES6_ExportAllFrom_Source2\""
`; `;
exports[`test ES6_ExportAllFrom_Source1.js 1`] = ` exports[`test ES6_ExportAllFrom_Source1.js 1`] = `
@ -283,8 +287,8 @@ declare export var numberValue1: number;
* @providesModule ES6_ExportAllFrom_Source1 * @providesModule ES6_ExportAllFrom_Source1
* @flow * @flow
*/ */
declare export var numberValue1: number;
" declare export var numberValue1: number;"
`; `;
exports[`test ES6_ExportAllFrom_Source2.js 1`] = ` exports[`test ES6_ExportAllFrom_Source2.js 1`] = `
@ -299,8 +303,8 @@ declare export var numberValue2: number;
* @providesModule ES6_ExportAllFrom_Source2 * @providesModule ES6_ExportAllFrom_Source2
* @flow * @flow
*/ */
declare export var numberValue2: number;
" declare export var numberValue2: number;"
`; `;
exports[`test ES6_ExportAllFromMulti.js 1`] = ` exports[`test ES6_ExportAllFromMulti.js 1`] = `
@ -310,9 +314,9 @@ declare export * from \"./ES6_ExportAllFrom_Source1\";
declare export * from \"./ES6_ExportAllFrom_Source2\"; declare export * from \"./ES6_ExportAllFrom_Source2\";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
declare export * from \"./ES6_ExportAllFrom_Source1\" declare export * from \"./ES6_ExportAllFrom_Source1\"
declare export * from \"./ES6_ExportAllFrom_Source2\" declare export * from \"./ES6_ExportAllFrom_Source2\""
"
`; `;
exports[`test ES6_ExportFrom_Intermediary1.js 1`] = ` exports[`test ES6_ExportFrom_Intermediary1.js 1`] = `
@ -330,8 +334,8 @@ declare export {
* @providesModule ES6_ExportFrom_Intermediary1 * @providesModule ES6_ExportFrom_Intermediary1
* @flow * @flow
*/ */
declare export {numberValue1, numberValue2 as numberValue2_renamed} from \"ES6_ExportFrom_Source1\"
" declare export {numberValue1, numberValue2 as numberValue2_renamed} from \"ES6_ExportFrom_Source1\""
`; `;
exports[`test ES6_ExportFrom_Intermediary2.js 1`] = ` exports[`test ES6_ExportFrom_Intermediary2.js 1`] = `
@ -349,8 +353,8 @@ declare export {
* @providesModule ES6_ExportFrom_Intermediary2 * @providesModule ES6_ExportFrom_Intermediary2
* @flow * @flow
*/ */
declare export {numberValue1, numberValue2 as numberValue2_renamed2} from \"ES6_ExportFrom_Source2\"
" declare export {numberValue1, numberValue2 as numberValue2_renamed2} from \"ES6_ExportFrom_Source2\""
`; `;
exports[`test ES6_ExportFrom_Source1.js 1`] = ` exports[`test ES6_ExportFrom_Source1.js 1`] = `
@ -366,9 +370,9 @@ declare export var numberValue2: number;
* @providesModule ES6_ExportFrom_Source1 * @providesModule ES6_ExportFrom_Source1
* @flow * @flow
*/ */
declare export var numberValue1: number; declare export var numberValue1: number;
declare export var numberValue2: number; declare export var numberValue2: number;"
"
`; `;
exports[`test ES6_ExportFrom_Source2.js 1`] = ` exports[`test ES6_ExportFrom_Source2.js 1`] = `
@ -384,9 +388,9 @@ declare export var numberValue2: number;
* @providesModule ES6_ExportFrom_Source2 * @providesModule ES6_ExportFrom_Source2
* @flow * @flow
*/ */
declare export var numberValue1: number; declare export var numberValue1: number;
declare export var numberValue2: number; declare export var numberValue2: number;"
"
`; `;
exports[`test ES6_Named1.js 1`] = ` exports[`test ES6_Named1.js 1`] = `
@ -416,20 +420,23 @@ declare export var varDeclNumber2: number;
* @providesModule ES6_Named1 * @providesModule ES6_Named1
* @flow * @flow
*/ */
var specifierNumber1 = 1; var specifierNumber1 = 1;
var specifierNumber2 = 2; var specifierNumber2 = 2;
var specifierNumber3 = 3; var specifierNumber3 = 3;
var groupedSpecifierNumber1 = 1; var groupedSpecifierNumber1 = 1;
var groupedSpecifierNumber2 = 2; var groupedSpecifierNumber2 = 2;
declare export {specifierNumber1} declare export {specifierNumber1}
declare export {specifierNumber2 as specifierNumber2Renamed} declare export {specifierNumber2 as specifierNumber2Renamed}
declare export {specifierNumber3} declare export {specifierNumber3}
declare export {groupedSpecifierNumber1, groupedSpecifierNumber2} declare export {groupedSpecifierNumber1, groupedSpecifierNumber2}
declare export function givesANumber(): number; declare export function givesANumber(): number;
declare export class NumberGenerator { givesANumber(): number } declare export class NumberGenerator { givesANumber(): number }
declare export var varDeclNumber1: number; declare export var varDeclNumber1: number;
declare export var varDeclNumber2: number; declare export var varDeclNumber2: number;"
"
`; `;
exports[`test ES6_Named2.js 1`] = ` exports[`test ES6_Named2.js 1`] = `
@ -457,18 +464,21 @@ declare export var varDeclNumber4: number;
* @providesModule ES6_Named2 * @providesModule ES6_Named2
* @flow * @flow
*/ */
var specifierNumber4 = 1; var specifierNumber4 = 1;
var specifierNumber5 = 2; var specifierNumber5 = 2;
var groupedSpecifierNumber3 = 1; var groupedSpecifierNumber3 = 1;
var groupedSpecifierNumber4 = 2; var groupedSpecifierNumber4 = 2;
declare export {specifierNumber4} declare export {specifierNumber4}
declare export {specifierNumber5 as specifierNumber5Renamed} declare export {specifierNumber5 as specifierNumber5Renamed}
declare export {groupedSpecifierNumber3, groupedSpecifierNumber4} declare export {groupedSpecifierNumber3, groupedSpecifierNumber4}
declare export function givesANumber2(): number; declare export function givesANumber2(): number;
declare export class NumberGenerator2 { givesANumber(): number } declare export class NumberGenerator2 { givesANumber(): number }
declare export var varDeclNumber3: number; declare export var varDeclNumber3: number;
declare export var varDeclNumber4: number; declare export var varDeclNumber4: number;"
"
`; `;
exports[`test ProvidesModuleA.js 1`] = ` exports[`test ProvidesModuleA.js 1`] = `
@ -487,12 +497,12 @@ exports.stringValue = \"str\";
* @providesModule A * @providesModule A
* @flow * @flow
*/ */
exports.numberValue1 = 42; exports.numberValue1 = 42;
exports.numberValue2 = 42; exports.numberValue2 = 42;
exports.numberValue3 = 42; exports.numberValue3 = 42;
exports.numberValue4 = 42; exports.numberValue4 = 42;
exports.stringValue = \"str\"; exports.stringValue = \"str\";"
"
`; `;
exports[`test ProvidesModuleCJSDefault.js 1`] = ` exports[`test ProvidesModuleCJSDefault.js 1`] = `
@ -509,8 +519,8 @@ module.exports = {
* @providesModule CJSDefault * @providesModule CJSDefault
* @flow * @flow
*/ */
module.exports = { numberValue: 42 };
" module.exports = { numberValue: 42 };"
`; `;
exports[`test ProvidesModuleD.js 1`] = ` exports[`test ProvidesModuleD.js 1`] = `
@ -519,11 +529,6 @@ exports[`test ProvidesModuleD.js 1`] = `
* @flow * @flow
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @providesModule D
* @flow
*/
" "
`; `;
@ -539,24 +544,12 @@ export default {
}; };
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @providesModule ES6Default
* @flow
*/
/*
export default {
numberValue: 42,
};
*/
" "
`; `;
exports[`test SideEffects.js 1`] = ` exports[`test SideEffects.js 1`] = `
"/* @flow */ "/* @flow */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
" "
`; `;
@ -854,271 +847,274 @@ var at3: number = numberValue9;
var at4: string = numberValue9; // Error: number ~> string var at4: string = numberValue9; // Error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// ===================== // // ===================== //
// == Path Resolution == // // == Path Resolution == //
// ===================== // // ===================== //
// @providesModule // @providesModule
import * as DefaultA from \"A\";
var a1: number = DefaultA.numberValue1;
var a2: string = DefaultA.numberValue1;
// Error: number ~> string // Error: number ~> string
// File path // File path
import * as DefaultB from \"./B\";
var b1: number = DefaultB.numberValue;
var b2: string = DefaultB.numberValue;
// Error: number ~> string // Error: number ~> string
// C.js exists, but not as a providesModule // C.js exists, but not as a providesModule
import DefaultC from \"C\";
// Error: No such module // Error: No such module
// @providesModule D exists, but not as a filename // @providesModule D exists, but not as a filename
import DefaultD from \"./D\";
// Error: No such module // Error: No such module
// ================================================ // // ================================================ //
// == CommonJS Clobbering Literal Exports -> ES6 == // // == CommonJS Clobbering Literal Exports -> ES6 == //
// ================================================ // // ================================================ //
import {doesntExist1} from \"CommonJS_Clobbering_Lit\";
// Error: Not an exported binding // Error: Not an exported binding
import {numberValue1} from \"CommonJS_Clobbering_Lit\";
var c1: number = numberValue1;
var c2: string = numberValue1;
// Error: number ~> string // Error: number ~> string
import {numberValue2 as numVal1} from \"CommonJS_Clobbering_Lit\";
var d1: number = numVal1;
var d2: string = numVal1;
// Error: number ~> string // Error: number ~> string
import CJS_Clobb_Lit from \"CommonJS_Clobbering_Lit\";
var e1: number = CJS_Clobb_Lit.numberValue3;
var e2: string = CJS_Clobb_Lit.numberValue3;
// Error: number ~> string // Error: number ~> string
CJS_Clobb_Lit.doesntExist;
// Error: doesntExist isn\'t a property // Error: doesntExist isn\'t a property
import * as CJS_Clobb_Lit_NS from \"CommonJS_Clobbering_Lit\";
var f1: number = CJS_Clobb_Lit_NS.numberValue4;
var f2: number = CJS_Clobb_Lit_NS.default.numberValue4;
CJS_Clobb_Lit_NS.default.default;
// Error: No \'default\' property on the exported obj // Error: No \'default\' property on the exported obj
var f3: string = CJS_Clobb_Lit_NS.numberValue4;
// Error: number ~> string // Error: number ~> string
var f4: string = CJS_Clobb_Lit_NS.default.numberValue5;
// Error: number ~> string // Error: number ~> string
// ============================================== // // ============================================== //
// == CommonJS Clobbering Class Exports -> ES6 == // // == CommonJS Clobbering Class Exports -> ES6 == //
// ============================================== // // ============================================== //
import {doesntExist2} from \"CommonJS_Clobbering_Class\";
// Error: Not an exported binding // Error: Not an exported binding
// The following import should error because class statics are not turned into // The following import should error because class statics are not turned into
// named exports for now. This avoids complexities with polymorphic static // named exports for now. This avoids complexities with polymorphic static
// members (where the polymophism is defined on the class itself rather than the // members (where the polymophism is defined on the class itself rather than the
// method). // method).
import {staticNumber1, baseProp, childProp} from \"CommonJS_Clobbering_Class\";
// Error // Error
import CJS_Clobb_Class from \"CommonJS_Clobbering_Class\";
new CJS_Clobb_Class();
new CJS_Clobb_Class().doesntExist;
// Error: Class has no \`doesntExist\` property // Error: Class has no \`doesntExist\` property
var h1: number = CJS_Clobb_Class.staticNumber2();
var h2: string = CJS_Clobb_Class.staticNumber2();
// Error: number ~> string // Error: number ~> string
var h3: number = new CJS_Clobb_Class().instNumber1();
var h4: string = new CJS_Clobb_Class().instNumber1();
// Error: number ~> string // Error: number ~> string
import * as CJS_Clobb_Class_NS from \"CommonJS_Clobbering_Class\";
new CJS_Clobb_Class_NS();
// Error: Namespace object isn\'t constructable // Error: Namespace object isn\'t constructable
var i1: number = CJS_Clobb_Class_NS.staticNumber3();
// Error: Class statics not copied to Namespace object // Error: Class statics not copied to Namespace object
var i2: number = new CJS_Clobb_Class_NS.default().instNumber2();
var i3: string = new CJS_Clobb_Class_NS.default().instNumber2();
// Error: number ~> string // Error: number ~> string
// =================================== // // =================================== //
// == CommonJS Named Exports -> ES6 == // // == CommonJS Named Exports -> ES6 == //
// =================================== // // =================================== //
import {doesntExist3} from \"CommonJS_Named\";
// Error: Not an exported binding // Error: Not an exported binding
import {numberValue2} from \"CommonJS_Named\";
var j1: number = numberValue2;
var j2: string = numberValue2;
// Error: number ~> string // Error: number ~> string
import {numberValue3 as numVal3} from \"CommonJS_Named\";
var k1: number = numVal3;
var k2: string = numVal3;
// Error: number ~> string // Error: number ~> string
import * as CJS_Named from \"CommonJS_Named\";
var l1: number = CJS_Named.numberValue1;
var l2: string = CJS_Named.numberValue1;
// Error: number ~> string // Error: number ~> string
CJS_Named.doesntExist;
// Error: doesntExist isn\'t a property // Error: doesntExist isn\'t a property
import * as CJS_Named_NS from \"CommonJS_Named\";
var m1: number = CJS_Named_NS.numberValue4;
var m2: string = CJS_Named_NS.default.numberValue4;
// Error: CommonJS_Named has no default export // Error: CommonJS_Named has no default export
var m3: string = CJS_Named_NS.numberValue4;
// Error: number ~> string // Error: number ~> string
////////////////////////////// //////////////////////////////
// == ES6 Default -> ES6 == // // == ES6 Default -> ES6 == //
////////////////////////////// //////////////////////////////
import {doesntExist4} from \"ES6_Default_AnonFunction1\";
// Error: Not an exported binding // Error: Not an exported binding
import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\";
var n1: number = ES6_Def_AnonFunc1();
var n2: string = ES6_Def_AnonFunc1();
// Error: number ~> string // Error: number ~> string
import ES6_Def_NamedFunc1 from \"ES6_Default_NamedFunction1\";
var o1: number = ES6_Def_NamedFunc1();
var o2: string = ES6_Def_NamedFunc1();
// Error: number ~> string // Error: number ~> string
import ES6_Def_NamedClass1 from \"ES6_Default_NamedClass1\";
var q1: number = new ES6_Def_NamedClass1().givesANum();
var q2: string = new ES6_Def_NamedClass1().givesANum();
// Error: number ~> string // Error: number ~> string
//////////////////////////// ////////////////////////////
// == ES6 Named -> ES6 == // // == ES6 Named -> ES6 == //
//////////////////////////// ////////////////////////////
// Error: Not an exported binding
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
///////////////////////////////////
// == ES6 Default -> CommonJS == //
///////////////////////////////////
// Error: \'doesntExist\' isn\'t an export
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
/////////////////////////////////
// == ES6 Named -> CommonJS == //
/////////////////////////////////
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
////////////////////////////////////////////////////////
// == ES6 Default+Named -> ES6 import Default+Named== //
////////////////////////////////////////////////////////
// Error: number ~> string
// Error: string ~> number
////////////////////////////////////////
// == Side-effect only ES6 imports == //
////////////////////////////////////////
//////////////////////////////////////////////
// == Suggest export name on likely typo == //
//////////////////////////////////////////////
// Error: Did you mean \`import {specifierNumber1} from ...\`?
// Error: Did you mean \`specifierNumber1\`?
///////////////////////////////////////////////////
// == Multi \`export *\` should combine exports == //
///////////////////////////////////////////////////
// Error: number ~> string
// Error: number ~> string
import * as DefaultA from \"A\";
var a1: number = DefaultA.numberValue1;
var a2: string = DefaultA.numberValue1;
import * as DefaultB from \"./B\";
var b1: number = DefaultB.numberValue;
var b2: string = DefaultB.numberValue;
import DefaultC from \"C\";
import DefaultD from \"./D\";
import {doesntExist1} from \"CommonJS_Clobbering_Lit\";
import {numberValue1} from \"CommonJS_Clobbering_Lit\";
var c1: number = numberValue1;
var c2: string = numberValue1;
import {numberValue2 as numVal1} from \"CommonJS_Clobbering_Lit\";
var d1: number = numVal1;
var d2: string = numVal1;
import CJS_Clobb_Lit from \"CommonJS_Clobbering_Lit\";
var e1: number = CJS_Clobb_Lit.numberValue3;
var e2: string = CJS_Clobb_Lit.numberValue3;
CJS_Clobb_Lit.doesntExist;
import * as CJS_Clobb_Lit_NS from \"CommonJS_Clobbering_Lit\";
var f1: number = CJS_Clobb_Lit_NS.numberValue4;
var f2: number = CJS_Clobb_Lit_NS.default.numberValue4;
CJS_Clobb_Lit_NS.default.default;
var f3: string = CJS_Clobb_Lit_NS.numberValue4;
var f4: string = CJS_Clobb_Lit_NS.default.numberValue5;
import {doesntExist2} from \"CommonJS_Clobbering_Class\";
import {staticNumber1, baseProp, childProp} from \"CommonJS_Clobbering_Class\";
import CJS_Clobb_Class from \"CommonJS_Clobbering_Class\";
new CJS_Clobb_Class();
new CJS_Clobb_Class().doesntExist;
var h1: number = CJS_Clobb_Class.staticNumber2();
var h2: string = CJS_Clobb_Class.staticNumber2();
var h3: number = new CJS_Clobb_Class().instNumber1();
var h4: string = new CJS_Clobb_Class().instNumber1();
import * as CJS_Clobb_Class_NS from \"CommonJS_Clobbering_Class\";
new CJS_Clobb_Class_NS();
var i1: number = CJS_Clobb_Class_NS.staticNumber3();
var i2: number = new CJS_Clobb_Class_NS.default().instNumber2();
var i3: string = new CJS_Clobb_Class_NS.default().instNumber2();
import {doesntExist3} from \"CommonJS_Named\";
import {numberValue2} from \"CommonJS_Named\";
var j1: number = numberValue2;
var j2: string = numberValue2;
import {numberValue3 as numVal3} from \"CommonJS_Named\";
var k1: number = numVal3;
var k2: string = numVal3;
import * as CJS_Named from \"CommonJS_Named\";
var l1: number = CJS_Named.numberValue1;
var l2: string = CJS_Named.numberValue1;
CJS_Named.doesntExist;
import * as CJS_Named_NS from \"CommonJS_Named\";
var m1: number = CJS_Named_NS.numberValue4;
var m2: string = CJS_Named_NS.default.numberValue4;
var m3: string = CJS_Named_NS.numberValue4;
import {doesntExist4} from \"ES6_Default_AnonFunction1\";
import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\";
var n1: number = ES6_Def_AnonFunc1();
var n2: string = ES6_Def_AnonFunc1();
import ES6_Def_NamedFunc1 from \"ES6_Default_NamedFunction1\";
var o1: number = ES6_Def_NamedFunc1();
var o2: string = ES6_Def_NamedFunc1();
import ES6_Def_NamedClass1 from \"ES6_Default_NamedClass1\";
var q1: number = new ES6_Def_NamedClass1().givesANum();
var q2: string = new ES6_Def_NamedClass1().givesANum();
import doesntExist5 from \"ES6_Named1\"; import doesntExist5 from \"ES6_Named1\";
// Error: Not an exported binding
import {specifierNumber1 as specifierNumber1_1} from \"ES6_Named1\"; import {specifierNumber1 as specifierNumber1_1} from \"ES6_Named1\";
var r1: number = specifierNumber1_1; var r1: number = specifierNumber1_1;
var r2: string = specifierNumber1_1; var r2: string = specifierNumber1_1;
// Error: number ~> string
import {specifierNumber2Renamed} from \"ES6_Named1\"; import {specifierNumber2Renamed} from \"ES6_Named1\";
var s1: number = specifierNumber2Renamed; var s1: number = specifierNumber2Renamed;
var s2: string = specifierNumber2Renamed; var s2: string = specifierNumber2Renamed;
// Error: number ~> string
import {specifierNumber3 as specifierNumber3Renamed} from \"ES6_Named1\"; import {specifierNumber3 as specifierNumber3Renamed} from \"ES6_Named1\";
var t1: number = specifierNumber3Renamed; var t1: number = specifierNumber3Renamed;
var t2: string = specifierNumber3Renamed; var t2: string = specifierNumber3Renamed;
// Error: number ~> string
import {groupedSpecifierNumber1, groupedSpecifierNumber2} from \"ES6_Named1\"; import {groupedSpecifierNumber1, groupedSpecifierNumber2} from \"ES6_Named1\";
var u1: number = groupedSpecifierNumber1; var u1: number = groupedSpecifierNumber1;
var u2: number = groupedSpecifierNumber2; var u2: number = groupedSpecifierNumber2;
var u3: string = groupedSpecifierNumber1; var u3: string = groupedSpecifierNumber1;
// Error: number ~> string
var u4: string = groupedSpecifierNumber2; var u4: string = groupedSpecifierNumber2;
// Error: number ~> string
import {givesANumber} from \"ES6_Named1\"; import {givesANumber} from \"ES6_Named1\";
var v1: number = givesANumber(); var v1: number = givesANumber();
var v2: string = givesANumber(); var v2: string = givesANumber();
// Error: number ~> string
import {NumberGenerator} from \"ES6_Named1\"; import {NumberGenerator} from \"ES6_Named1\";
var w1: number = new NumberGenerator().givesANumber(); var w1: number = new NumberGenerator().givesANumber();
var w2: string = new NumberGenerator().givesANumber(); var w2: string = new NumberGenerator().givesANumber();
// Error: number ~> string
import {varDeclNumber1, varDeclNumber2} from \"ES6_Named1\"; import {varDeclNumber1, varDeclNumber2} from \"ES6_Named1\";
var x1: number = varDeclNumber1; var x1: number = varDeclNumber1;
var x2: number = varDeclNumber2; var x2: number = varDeclNumber2;
var x3: string = varDeclNumber1; var x3: string = varDeclNumber1;
// Error: number ~> string
var x4: string = varDeclNumber2; var x4: string = varDeclNumber2;
// Error: number ~> string
import {numberValue1 as numberValue4} from \"ES6_ExportFrom_Intermediary1\"; import {numberValue1 as numberValue4} from \"ES6_ExportFrom_Intermediary1\";
var aa1: number = numberValue4; var aa1: number = numberValue4;
var aa2: string = numberValue4; var aa2: string = numberValue4;
// Error: number ~> string
import {numberValue2_renamed} from \"ES6_ExportFrom_Intermediary1\"; import {numberValue2_renamed} from \"ES6_ExportFrom_Intermediary1\";
var ab1: number = numberValue2_renamed; var ab1: number = numberValue2_renamed;
var ab2: string = numberValue2_renamed; var ab2: string = numberValue2_renamed;
// Error: number ~> string
import {numberValue1 as numberValue5} from \"ES6_ExportAllFrom_Intermediary1\"; import {numberValue1 as numberValue5} from \"ES6_ExportAllFrom_Intermediary1\";
var ac1: number = numberValue5; var ac1: number = numberValue5;
var ac2: string = numberValue5; var ac2: string = numberValue5;
// Error: number ~> string
///////////////////////////////////
// == ES6 Default -> CommonJS == //
///////////////////////////////////
require(\"ES6_Default_AnonFunction2\").doesntExist; require(\"ES6_Default_AnonFunction2\").doesntExist;
// Error: \'doesntExist\' isn\'t an export
var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default; var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default;
var ad1: number = ES6_Def_AnonFunc2(); var ad1: number = ES6_Def_AnonFunc2();
var ad2: string = ES6_Def_AnonFunc2(); var ad2: string = ES6_Def_AnonFunc2();
// Error: number ~> string
var ES6_Def_NamedFunc2 = require(\"ES6_Default_NamedFunction2\").default; var ES6_Def_NamedFunc2 = require(\"ES6_Default_NamedFunction2\").default;
var ae1: number = ES6_Def_NamedFunc2(); var ae1: number = ES6_Def_NamedFunc2();
var ae2: string = ES6_Def_NamedFunc2(); var ae2: string = ES6_Def_NamedFunc2();
// Error: number ~> string
var ES6_Def_NamedClass2 = require(\"ES6_Default_NamedClass2\").default; var ES6_Def_NamedClass2 = require(\"ES6_Default_NamedClass2\").default;
var ag1: number = new ES6_Def_NamedClass2().givesANum(); var ag1: number = new ES6_Def_NamedClass2().givesANum();
var ag2: string = new ES6_Def_NamedClass2().givesANum(); var ag2: string = new ES6_Def_NamedClass2().givesANum();
// Error: number ~> string
/////////////////////////////////
// == ES6 Named -> CommonJS == //
/////////////////////////////////
var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4; var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4;
var ah1: number = specifierNumber4; var ah1: number = specifierNumber4;
var ah2: string = specifierNumber4; var ah2: string = specifierNumber4;
// Error: number ~> string
var specifierNumber5Renamed = require(\"ES6_Named2\").specifierNumber5Renamed; var specifierNumber5Renamed = require(\"ES6_Named2\").specifierNumber5Renamed;
var ai1: number = specifierNumber5Renamed; var ai1: number = specifierNumber5Renamed;
var ai2: string = specifierNumber5Renamed; var ai2: string = specifierNumber5Renamed;
// Error: number ~> string
var groupedSpecifierNumber3 = require(\"ES6_Named2\").groupedSpecifierNumber3; var groupedSpecifierNumber3 = require(\"ES6_Named2\").groupedSpecifierNumber3;
var groupedSpecifierNumber4 = require(\"ES6_Named2\").groupedSpecifierNumber4; var groupedSpecifierNumber4 = require(\"ES6_Named2\").groupedSpecifierNumber4;
var aj1: number = groupedSpecifierNumber3; var aj1: number = groupedSpecifierNumber3;
var aj2: number = groupedSpecifierNumber4; var aj2: number = groupedSpecifierNumber4;
var aj3: string = groupedSpecifierNumber3; var aj3: string = groupedSpecifierNumber3;
// Error: number ~> string
var aj4: string = groupedSpecifierNumber4; var aj4: string = groupedSpecifierNumber4;
// Error: number ~> string
var givesANumber2 = require(\"ES6_Named2\").givesANumber2; var givesANumber2 = require(\"ES6_Named2\").givesANumber2;
var ak1: number = givesANumber2(); var ak1: number = givesANumber2();
var ak2: string = givesANumber2(); var ak2: string = givesANumber2();
// Error: number ~> string
var NumberGenerator2 = require(\"ES6_Named2\").NumberGenerator2; var NumberGenerator2 = require(\"ES6_Named2\").NumberGenerator2;
var al1: number = new NumberGenerator2().givesANumber(); var al1: number = new NumberGenerator2().givesANumber();
var al2: string = new NumberGenerator2().givesANumber(); var al2: string = new NumberGenerator2().givesANumber();
// Error: number ~> string
var varDeclNumber3 = require(\"ES6_Named2\").varDeclNumber3; var varDeclNumber3 = require(\"ES6_Named2\").varDeclNumber3;
var varDeclNumber4 = require(\"ES6_Named2\").varDeclNumber4; var varDeclNumber4 = require(\"ES6_Named2\").varDeclNumber4;
var am1: number = varDeclNumber3; var am1: number = varDeclNumber3;
var am2: number = varDeclNumber4; var am2: number = varDeclNumber4;
var am3: string = varDeclNumber3; var am3: string = varDeclNumber3;
// Error: number ~> string
var am4: string = varDeclNumber4; var am4: string = varDeclNumber4;
// Error: number ~> string
var numberValue6 = require(\"ES6_ExportFrom_Intermediary2\").numberValue1; var numberValue6 = require(\"ES6_ExportFrom_Intermediary2\").numberValue1;
var ap1: number = numberValue6; var ap1: number = numberValue6;
var ap2: string = numberValue6; var ap2: string = numberValue6;
// Error: number ~> string
var numberValue2_renamed2 = require( var numberValue2_renamed2 = require(
\"ES6_ExportFrom_Intermediary2\" \"ES6_ExportFrom_Intermediary2\"
).numberValue2_renamed2; ).numberValue2_renamed2;
var aq1: number = numberValue2_renamed2; var aq1: number = numberValue2_renamed2;
var aq2: string = numberValue2_renamed2; var aq2: string = numberValue2_renamed2;
// Error: number ~> string
var numberValue7 = require(\"ES6_ExportAllFrom_Intermediary2\").numberValue2; var numberValue7 = require(\"ES6_ExportAllFrom_Intermediary2\").numberValue2;
var ar1: number = numberValue7; var ar1: number = numberValue7;
var ar2: string = numberValue7; var ar2: string = numberValue7;
// Error: number ~> string
////////////////////////////////////////////////////////
// == ES6 Default+Named -> ES6 import Default+Named== //
////////////////////////////////////////////////////////
import defaultNum, {str as namedStr} from \"./ES6_DefaultAndNamed\"; import defaultNum, {str as namedStr} from \"./ES6_DefaultAndNamed\";
var as1: number = defaultNum; var as1: number = defaultNum;
var as2: string = defaultNum; var as2: string = defaultNum;
// Error: number ~> string
var as3: string = namedStr; var as3: string = namedStr;
var as4: number = namedStr; var as4: number = namedStr;
// Error: string ~> number
////////////////////////////////////////
// == Side-effect only ES6 imports == //
////////////////////////////////////////
import \"./SideEffects\"; import \"./SideEffects\";
//////////////////////////////////////////////
// == Suggest export name on likely typo == //
//////////////////////////////////////////////
import specifierNumber1 from \"ES6_Named1\"; import specifierNumber1 from \"ES6_Named1\";
// Error: Did you mean \`import {specifierNumber1} from ...\`?
import {specifierNumber} from \"ES6_Named1\"; import {specifierNumber} from \"ES6_Named1\";
// Error: Did you mean \`specifierNumber1\`?
///////////////////////////////////////////////////
// == Multi \`export *\` should combine exports == //
///////////////////////////////////////////////////
import {numberValue1 as numberValue8, numberValue2 as numberValue9} from \"./ES6_ExportAllFromMulti\"; import {numberValue1 as numberValue8, numberValue2 as numberValue9} from \"./ES6_ExportAllFromMulti\";
var at1: number = numberValue8; var at1: number = numberValue8;
var at2: string = numberValue8; var at2: string = numberValue8;
// Error: number ~> string
var at3: number = numberValue9; var at3: number = numberValue9;
var at4: string = numberValue9; var at4: string = numberValue9; // Error: number ~> string"
"
`; `;

View File

@ -7,14 +7,13 @@ declare function foo<X>(x: X): X;
(foo(\"hello\"): number); // OK (foo(\"hello\"): number); // OK
(foo(false): void); // error, boolean ~/~ undefined (foo(false): void); // error, boolean ~/~ undefined
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// OK
// OK
// error, boolean ~/~ undefined
declare function foo(x: number): string; declare function foo(x: number): string;
declare function foo(x: string): number; declare function foo(x: string): number;
declare function foo<X>(x: X): X; declare function foo<X>(x: X): X;
(foo(0): string); (foo(0): string);
// OK
(foo(\"hello\"): number); (foo(\"hello\"): number);
(foo(false): void); // OK
" (foo(false): void); // error, boolean ~/~ undefined"
`; `;

View File

@ -26,27 +26,27 @@ import declare_m_e_with_declare_var_e from \"declare_m_e_with_declare_var_e\";
(declare_m_e_with_declare_var_e: string); // Error: number ~> string (declare_m_e_with_declare_var_e: string); // Error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
import declare_module_exports from \"declare_module_exports\";
(declare_module_exports: number);
(declare_module_exports: string);
// Error: number ~> string // Error: number ~> string
// Error: Has no named export \"str\"! // Error: Has no named export \"str\"!
import {str} from \"declare_m_e_with_other_value_declares\";
import type {str2} from \"declare_m_e_with_other_type_declares\";
(\"asdf\": str2);
(42: str2);
// Error: number ~> string // Error: number ~> string
/** /**
* \`declare var exports\` is deprecated, so we have a grace period where both * \`declare var exports\` is deprecated, so we have a grace period where both
* syntaxes will work. * syntaxes will work.
*/ */
// Error: number ~> string
// Error: number ~> string
import declare_module_exports from \"declare_module_exports\";
(declare_module_exports: number);
(declare_module_exports: string);
import {str} from \"declare_m_e_with_other_value_declares\";
import type {str2} from \"declare_m_e_with_other_type_declares\";
(\"asdf\": str2);
(42: str2);
import DEPRECATED__declare_var_exports from \"DEPRECATED__declare_var_exports\"; import DEPRECATED__declare_var_exports from \"DEPRECATED__declare_var_exports\";
(DEPRECATED__declare_var_exports: number); (DEPRECATED__declare_var_exports: number);
(DEPRECATED__declare_var_exports: string); (DEPRECATED__declare_var_exports: string);
// Error: number ~> string
import declare_m_e_with_declare_var_e from \"declare_m_e_with_declare_var_e\"; import declare_m_e_with_declare_var_e from \"declare_m_e_with_declare_var_e\";
(declare_m_e_with_declare_var_e: number); (declare_m_e_with_declare_var_e: number);
(declare_m_e_with_declare_var_e: string); (declare_m_e_with_declare_var_e: string); // Error: number ~> string"
"
`; `;

View File

@ -30,13 +30,6 @@ declare module \"declare_m_e_with_declare_var_e\" {
declare var exports: string; declare var exports: string;
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* \`declare var exports\` is deprecated, so we have a grace period where both
* syntaxes will work.
*/
/**
* Ensure that, if both are present, \`declare module.exports\` wins
*/
declare module \"declare_module_exports\" { declare module \"declare_module_exports\" {
declare module.exports: number; declare module.exports: number;
} }
@ -48,12 +41,18 @@ declare module \"declare_m_e_with_other_type_declares\" {
declare module.exports: number; declare module.exports: number;
declare type str2 = string; declare type str2 = string;
} }
/**
* \`declare var exports\` is deprecated, so we have a grace period where both
* syntaxes will work.
*/
declare module \"DEPRECATED__declare_var_exports\" { declare module \"DEPRECATED__declare_var_exports\" {
declare var exports: number; declare var exports: number;
/**
* Ensure that, if both are present, \`declare module.exports\` wins
*/
} }
declare module \"declare_m_e_with_declare_var_e\" { declare module \"declare_m_e_with_declare_var_e\" {
declare module.exports: number; declare module.exports: number;
declare var exports: string; declare var exports: string;
} }"
"
`; `;

View File

@ -33,30 +33,31 @@ blah(0, 0);
/** /**
* @flow * @flow
*/ */
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// == Import Declared Type Alias From Declared Module == // // == Import Declared Type Alias From Declared Module == //
////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////
// Error: string to int
// works
// works
//////////////////////////////////////////////////////////
// == Declared Module with exports prop (issue 880) == //
////////////////////////////////////////////////////////
// error : {toz : number} ~> string
// error : number ~> A
// error : string ~> number
import type {baz} from \"ModuleAliasFoo\"; import type {baz} from \"ModuleAliasFoo\";
import {foo} from \"ModuleAliasFoo\"; import {foo} from \"ModuleAliasFoo\";
var k1: baz = 42; var k1: baz = 42;
var k2: baz = \"shab\"; var k2: baz = \"shab\";
// Error: string to int
var k3: toz = foo(k1); var k3: toz = foo(k1);
// works
import type {toz} from \"ModuleAliasFoo\"; import type {toz} from \"ModuleAliasFoo\";
var k4: toz = foo(k1); var k4: toz = foo(k1);
// works
//////////////////////////////////////////////////////////
// == Declared Module with exports prop (issue 880) == //
////////////////////////////////////////////////////////
import blah from \"foo\"; import blah from \"foo\";
import type {Foo, Bar, Id} from \"foo\"; import type {Foo, Bar, Id} from \"foo\";
blah(0, 0); blah(0, 0);
({ toz: 3 }: Foo); ({ toz: 3 }: Foo);
// error : {toz : number} ~> string
(3: Bar); (3: Bar);
(\"lol\": Id<number>); // error : number ~> A
" (\"lol\": Id<number>); // error : string ~> number"
`; `;

View File

@ -12,12 +12,12 @@ declare module ModuleAliasFoo {
/** /**
* @flow * @flow
*/ */
declare module ModuleAliasFoo { declare module ModuleAliasFoo {
declare type baz = number; declare type baz = number;
declare type toz = string; declare type toz = string;
declare function foo(bar: baz): toz; declare function foo(bar: baz): toz;
} }"
"
`; `;
exports[`test declare_type_exports.js 1`] = ` exports[`test declare_type_exports.js 1`] = `
@ -40,13 +40,16 @@ declare module \'foo\' {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
declare module \"foo\" { declare module \"foo\" {
declare class A { toz: number } declare class A { toz: number }
declare var n: string; declare var n: string;
declare type Foo = typeof n; declare type Foo = typeof n;
declare type Bar = A; declare type Bar = A;
declare type Id<T> = T; declare type Id<T> = T;
declare var exports: { (a: number, b: number): number }; declare var exports: { (a: number, b: number): number };
} }"
"
`; `;

View File

@ -31,20 +31,6 @@ class PropVariance<+Out,-In> {
con_dict2: {-[k:string]: In}; // ok con_dict2: {-[k:string]: In}; // ok
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error on both targs (A ~/~> B)
// OK for both targs (B ~> A)
// error
// error
// error
// ok
// ok
// error
// error
// error
// ok
// error
// error
// ok
class Variance<+Out, -In> { class Variance<+Out, -In> {
foo(x: Out): Out { foo(x: Out): Out {
return x; return x;
@ -53,25 +39,39 @@ class Variance<+Out, -In> {
return y; return y;
} }
} }
class A {} class A {}
class B extends A {} class B extends A {}
function subtyping(v1: Variance<A, B>, v2: Variance<B, A>) { function subtyping(v1: Variance<A, B>, v2: Variance<B, A>) {
(v1: Variance<B, A>); (v1: Variance<B, A>);
(v2: Variance<A, B>); // error on both targs (A ~/~> B)
(v2: Variance<A, B>); // OK for both targs (B ~> A)
} }
class PropVariance<+Out, -In> { class PropVariance<+Out, -In> {
inv1: Out; inv1: Out;
// error
inv2: In; inv2: In;
// error
-co1: Out; -co1: Out;
// error
-co2: In; -co2: In;
// ok
+con1: Out; +con1: Out;
// ok
+con2: In; +con2: In;
// error
inv_dict1: { [k: string]: Out }; inv_dict1: { [k: string]: Out };
// error
inv_dict2: { [k: string]: In }; inv_dict2: { [k: string]: In };
// error
co_dict1: { +[k: string]: Out }; co_dict1: { +[k: string]: Out };
// ok
co_dict2: { +[k: string]: In }; co_dict2: { +[k: string]: In };
// error
con_dict1: { -[k: string]: Out }; con_dict1: { -[k: string]: Out };
con_dict2: { -[k: string]: In }; // error
} con_dict2: { -[k: string]: In }; // ok
" }"
`; `;

View File

@ -9,11 +9,12 @@ var x = null;
f(x); f(x);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* demo */ /* demo */
//...
function f(x) { function f(x) {
return 42 / x; return 42 / x;
} }
var x = null; var x = null;
f(x); //...
" f(x);"
`; `;

View File

@ -20,26 +20,31 @@ a.onLoad(callback);
module.exports = A; module.exports = A;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @providesModule Demo */ /* @providesModule Demo */
// instance field declaration
class A { class A {
x: number; x: number;
// instance field declaration
constructor(x) { constructor(x) {
this.x = x; this.x = x;
} }
getX() { getX() {
return this.x; return this.x;
} }
onLoad(callback) { onLoad(callback) {
return callback(this.getX()); return callback(this.getX());
} }
} }
function callback(x: string) { function callback(x: string) {
return x.length; return x.length;
} }
var a = new A(42); var a = new A(42);
a.onLoad(callback); a.onLoad(callback);
module.exports = A;
" module.exports = A;"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
@ -48,6 +53,6 @@ exports[`test B.js 1`] = `
var z = new A(\"42\").getX(); var z = new A(\"42\").getX();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var A = require(\"Demo\"); var A = require(\"Demo\");
var z = new A(\"42\").getX();
" var z = new A(\"42\").getX();"
`; `;

View File

@ -1,15 +1,13 @@
exports[`test A.js 1`] = ` exports[`test A.js 1`] = `
"require(\'./C\'); "require(\'./C\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./C\"); require(\"./C\");"
"
`; `;
exports[`test B.js 1`] = ` exports[`test B.js 1`] = `
"require(\'./C\'); "require(\'./C\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./C\"); require(\"./C\");"
"
`; `;
exports[`test C.js 1`] = ` exports[`test C.js 1`] = `
@ -21,50 +19,41 @@ require(\'./G\');
require(\"./D\"); require(\"./D\");
require(\"./E\"); require(\"./E\");
require(\"./F\"); require(\"./F\");
require(\"./G\"); require(\"./G\");"
"
`; `;
exports[`test D.js 1`] = ` exports[`test D.js 1`] = `
"require(\'./I\'); "require(\'./I\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./I\"); require(\"./I\");"
"
`; `;
exports[`test E.js 1`] = ` exports[`test E.js 1`] = `
"require(\'./I\'); "require(\'./I\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./I\"); require(\"./I\");"
"
`; `;
exports[`test F.js 1`] = ` exports[`test F.js 1`] = `
"// empty "// empty
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// empty
" "
`; `;
exports[`test G.js 1`] = ` exports[`test G.js 1`] = `
"require(\'./H\'); "require(\'./H\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./H\"); require(\"./H\");"
"
`; `;
exports[`test H.js 1`] = ` exports[`test H.js 1`] = `
"// empty "// empty
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// empty
" "
`; `;
exports[`test I.js 1`] = ` exports[`test I.js 1`] = `
"require(\'./A\'); "require(\'./A\');
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
require(\"./A\"); require(\"./A\");"
"
`; `;

View File

@ -12,23 +12,22 @@ let d = zs[1]; // run off the end
let [...e] = 0; let [...e] = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// retain tuple info
// run off the end
// error: number ~> void
// error: string ~> void
// error: boolean ~> void
// error: number|string|boolean ~> void
let xs = [ 0, \"\", true ]; let xs = [ 0, \"\", true ];
let [ a, ...ys ] = xs; let [ a, ...ys ] = xs;
let [ b, ...zs ] = ys; let [ b, ...zs ] = ys;
let c = zs[0]; let c = zs[0];
// retain tuple info
let d = zs[1]; let d = zs[1];
// run off the end
(a: void); (a: void);
// error: number ~> void
(b: void); (b: void);
// error: string ~> void
(c: void); (c: void);
// error: boolean ~> void
(d: void); (d: void);
let [ ...e ] = 0; // error: number|string|boolean ~> void
" let [ ...e ] = 0;"
`; `;
exports[`test computed.js 1`] = ` exports[`test computed.js 1`] = `
@ -42,17 +41,15 @@ var { [key]: val2 } = { key: \"val\" };
var { [\"key\"]: val3, ...spread } = { key: \"val\" }; var { [\"key\"]: val3, ...spread } = { key: \"val\" };
(spread.key: void); // error (gasp!) in general we don\'t know if a computed prop should be excluded from spread (spread.key: void); // error (gasp!) in general we don\'t know if a computed prop should be excluded from spread
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: string ~> void
// ok (gasp!) by existing StrT -> ElemT rule
// error (gasp!) in general we don\'t know if a computed prop should be excluded from spread
var { [\"key\"]: val1 } = { key: \"val\" }; var { [\"key\"]: val1 } = { key: \"val\" };
(val1: void); (val1: void);
// error: string ~> void
var key: string = \"key\"; var key: string = \"key\";
var { [key]: val2 } = { key: \"val\" }; var { [key]: val2 } = { key: \"val\" };
(val2: void); (val2: void);
// ok (gasp!) by existing StrT -> ElemT rule
var { [\"key\"]: val3, ...spread } = { key: \"val\" }; var { [\"key\"]: val3, ...spread } = { key: \"val\" };
(spread.key: void); (spread.key: void); // error (gasp!) in general we don\'t know if a computed prop should be excluded from spread"
"
`; `;
exports[`test defaults.js 1`] = ` exports[`test defaults.js 1`] = `
@ -140,90 +137,104 @@ function obj_prop_union2({p}:{p:number}|{p:string}={p:true}) {}
function default_expr_scope({a, b = a}) {} function default_expr_scope({a, b = a}) {}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// errors:
// * number ~> void, from default on _.p.q
// * boolean ~> void, from default on _.p
// * string ~> void, from default on _
// * null ~> void, from call below
// ok
// ok
// ok
// ok, provides add\'l lower bound
// errors:
// * number ~> void, from default on o.p.q
// * boolean ~> void, from default on o.p
// * string ~> void, from default on o
// * null ~> void, from call below
// ok
// ok
// ok
// ok, provides add\'l lower bound
// errors:
// * number ~> void, from default on _.p
// * string ~> void, from default on _
// * null ~> void, from call below
// ok
// ok
// ok
// error: boolean ~> string
// error: number ~> string
// error: string ~> void
// error: boolean ~> string
// error: number ~> string
// error: string ~> void
// error: property \`x\` cannot be accessed on null
// error: expected object instead of number
// error: element 0 cannot be accessed on null
// error: expected array instead of null
// Default values in destructuring unwrap optional types
// ok
// ok
// union-like upper bounds preserved through destructuring
// TODO: union-of-objects upper bounds preserved through destructuring
function obj_prop_fun({ p: { q = 0 } = { q: true } } = { p: { q: \"\" } }) { function obj_prop_fun({ p: { q = 0 } = { q: true } } = { p: { q: \"\" } }) {
// errors:
// * number ~> void, from default on _.p.q
// * boolean ~> void, from default on _.p
// * string ~> void, from default on _
// * null ~> void, from call below
(q: void); (q: void);
} }
obj_prop_fun(); obj_prop_fun();
// ok
obj_prop_fun({}); obj_prop_fun({});
// ok
obj_prop_fun({ p: {} }); obj_prop_fun({ p: {} });
// ok
obj_prop_fun({ p: { q: null } }); obj_prop_fun({ p: { q: null } });
// ok, provides add\'l lower bound
function obj_prop_var(o = { p: { q: \"\" } }) { function obj_prop_var(o = { p: { q: \"\" } }) {
var { p: { q = 0 } = { q: true } } = o; var { p: { q = 0 } = { q: true } } = o;
// errors:
// * number ~> void, from default on o.p.q
// * boolean ~> void, from default on o.p
// * string ~> void, from default on o
// * null ~> void, from call below
(q: void); (q: void);
} }
obj_prop_var(); obj_prop_var();
// ok
obj_prop_var({}); obj_prop_var({});
// ok
obj_prop_var({ p: {} }); obj_prop_var({ p: {} });
// ok
obj_prop_var({ p: { q: null } }); obj_prop_var({ p: { q: null } });
// ok, provides add\'l lower bound
function obj_rest( function obj_rest(
{ p: { q, ...o } = { q: 0, r: 0 } } = { p: { q: 0, r: \"\" } } { p: { q, ...o } = { q: 0, r: 0 } } = { p: { q: 0, r: \"\" } }
) { ) {
// errors:
// * number ~> void, from default on _.p
// * string ~> void, from default on _
// * null ~> void, from call below
(o.r: void); (o.r: void);
} }
obj_rest(); obj_rest();
// ok
obj_rest({}); obj_rest({});
// ok
obj_rest({ p: {} }); obj_rest({ p: {} });
// ok
obj_rest({ p: { q: 0, r: null } }); obj_rest({ p: { q: 0, r: null } });
function obj_prop_annot({ p = true }: { p: string } = { p: 0 }) {
(p: void); function obj_prop_annot(
{
// error: boolean ~> string
p = true
}: { p: string } = {
// error: number ~> string
p: 0
}
) {
(p: void); // error: string ~> void
} }
var { p = true }: { p: string } = { p: 0 };
var {
// error: boolean ~> string
p = true
}: { p: string } = {
// error: number ~> string
p: 0
};
(p: void); (p: void);
// error: string ~> void
function obj_prop_err({ x: { y } } = null) {} function obj_prop_err({ x: { y } } = null) {}
// error: property \`x\` cannot be accessed on null
function obj_rest_err({ ...o } = 0) {} function obj_rest_err({ ...o } = 0) {}
// error: expected object instead of number
function arr_elem_err([ x ] = null) {} function arr_elem_err([ x ] = null) {}
// error: element 0 cannot be accessed on null
function arr_rest_err([ ...a ] = null) {} function arr_rest_err([ ...a ] = null) {}
// error: expected array instead of null
function gen<T>(x: T, { p = x }: { p: T }): T { function gen<T>(x: T, { p = x }: { p: T }): T {
return p; return p;
} }
// Default values in destructuring unwrap optional types
obj_prop_fun(({}: { p?: { q?: null } })); obj_prop_fun(({}: { p?: { q?: null } }));
// ok
obj_prop_var(({}: { p?: { q?: null } })); obj_prop_var(({}: { p?: { q?: null } }));
// ok
// union-like upper bounds preserved through destructuring
function obj_prop_opt({ p }: { p?: string } = { p: 0 }) {} function obj_prop_opt({ p }: { p?: string } = { p: 0 }) {}
function obj_prop_maybe({ p }: { p: ?string } = { p: 0 }) {} function obj_prop_maybe({ p }: { p: ?string } = { p: 0 }) {}
function obj_prop_union({ p }: { p: number | string } = { p: true }) {} function obj_prop_union({ p }: { p: number | string } = { p: true }) {}
// TODO: union-of-objects upper bounds preserved through destructuring
function obj_prop_union2({ p }: { p: number } | { p: string } = { p: true }) {} function obj_prop_union2({ p }: { p: number } | { p: string } = { p: true }) {}
function default_expr_scope({ a, b = a }) {}
" function default_expr_scope({ a, b = a }) {}"
`; `;
exports[`test destructuring.js 1`] = ` exports[`test destructuring.js 1`] = `
@ -299,70 +310,81 @@ var cp1_err: string = childprop1; // Error: number ~> string
var cp2: number = others.childprop1; var cp2: number = others.childprop1;
var cp2_err: string = others.childprop2; // Error: number ~> string var cp2_err: string = others.childprop2; // Error: number ~> string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error on foo
// error on baz
// error, baz doesn\'t exist
// no error, rest is unsealed
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
// Error: number ~> string
declare var a: string; declare var a: string;
declare var b: string; declare var b: string;
declare var c: string; declare var c: string;
[ { a1: a, b }, c ] = [ { a1: 0, b: 1 }, 2 ]; [ { a1: a, b }, c ] = [ { a1: 0, b: 1 }, 2 ];
var { m } = { m: 0 }; var { m } = { m: 0 };
({ m } = { m: m }); ({ m } = { m: m });
var obj; var obj;
({ n: obj.x } = { n: 3 }); ({ n: obj.x } = { n: 3 });
[ obj.x ] = [ \"foo\" ]; [ obj.x ] = [ \"foo\" ];
function foo({ p, z: [ r ] }) { function foo({ p, z: [ r ] }) {
a = p; a = p;
b = z; b = z;
c = r; c = r;
} }
foo({ p: 0, z: [ 1, 2 ] }); foo({ p: 0, z: [ 1, 2 ] });
[ a, , b, ...c ] = [ 0, 1, true, 3 ]; [ a, , b, ...c ] = [ 0, 1, true, 3 ];
function bar({ x, ...z }) { function bar({ x, ...z }) {
var o: { x: string, y: number } = z; var o: { x: string, y: number } = z;
} }
bar({ x: \"\", y: 0 }); bar({ x: \"\", y: 0 });
var spread = { y: \"\" }; var spread = { y: \"\" };
var extend: { x: number, y: string, z: boolean } = { x: 0, ...spread }; var extend: { x: number, y: string, z: boolean } = { x: 0, ...spread };
function qux(_: { a: number }) {} function qux(_: { a: number }) {}
qux({ a: \"\" }); qux({ a: \"\" });
function corge({ b }: { b: string }) {} function corge({ b }: { b: string }) {}
corge({ b: 0 }); corge({ b: 0 });
var { n }: { n: number } = { n: \"\" }; var { n }: { n: number } = { n: \"\" };
function test() { function test() {
var { foo } = { bar: 123 }; var { foo } = { bar: 123 };
var { bar, baz } = { bar: 123 }; // error on foo
var { bar, baz } = { bar: 123 }; // error on baz
} }
function test() { function test() {
var x = { foo: \"abc\", bar: 123 }; var x = { foo: \"abc\", bar: 123 };
var { foo, ...rest } = x; var { foo, ...rest } = x;
(x.baz: string); (x.baz: string);
(rest.baz: string); // error, baz doesn\'t exist
(rest.baz: string); // no error, rest is unsealed
} }
module.exports = corge; module.exports = corge;
class Base { class Base {
baseprop1: number; baseprop1: number;
baseprop2: number; baseprop2: number;
} }
class Child extends Base { class Child extends Base {
childprop1: number; childprop1: number;
childprop2: number; childprop2: number;
} }
var { baseprop1, childprop1, ...others } = new Child(); var { baseprop1, childprop1, ...others } = new Child();
var bp1: number = baseprop1; var bp1: number = baseprop1;
var bp1_err: string = baseprop1; var bp1_err: string = baseprop1;
// Error: number ~> string
var bp2: number = others.baseprop2; var bp2: number = others.baseprop2;
var bp2_err: string = others.baseprop2; var bp2_err: string = others.baseprop2;
// Error: number ~> string
var cp1: number = childprop1; var cp1: number = childprop1;
var cp1_err: string = childprop1; var cp1_err: string = childprop1;
// Error: number ~> string
var cp2: number = others.childprop1; var cp2: number = others.childprop1;
var cp2_err: string = others.childprop2; var cp2_err: string = others.childprop2; // Error: number ~> string"
"
`; `;
exports[`test destructuring_param.js 1`] = ` exports[`test destructuring_param.js 1`] = `
@ -379,27 +401,24 @@ exports[`test destructuring_param.js 1`] = `
// return a + b + c + d; // return a + b + c + d;
// } // }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
function f(a, { b }) {
return a + b;
}
// TODO: These throw errors when parsing. // TODO: These throw errors when parsing.
// function g(a, { a }) { // function g(a, { a }) {
// return a; // return a;
// } // }
// function h({ a, { b } }, { c }, { { d } }) { // function h({ a, { b } }, { c }, { { d } }) {
// return a + b + c + d; // return a + b + c + d;
// } // }"
function f(a, { b }) {
return a + b;
}
"
`; `;
exports[`test eager.js 1`] = ` exports[`test eager.js 1`] = `
"var x; "var x;
({x} = null); // error, property \`x\` can not be accessed on \`null\` ({x} = null); // error, property \`x\` can not be accessed on \`null\`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, property \`x\` can not be accessed on \`null\`
var x; var x;
({ x } = null); ({ x } = null); // error, property \`x\` can not be accessed on \`null\`"
"
`; `;
exports[`test poly.js 1`] = ` exports[`test poly.js 1`] = `
@ -437,44 +456,45 @@ function arr_rest_pattern<X>([ _, ...a ] : ArrRest<X>) { // a: [X]
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// prop: X
// prop: X
// elem: X
// elem: X
// proj: X
// proj: X
// nonsense
// r: X[]
// o: { x: X }
// o: { x: X }
// a: [X]
// a: [X]
function obj_pattern<X>({ prop }: { prop: X }) {} function obj_pattern<X>({ prop }: { prop: X }) {}
// prop: X
type Prop<X> = { prop: X }; type Prop<X> = { prop: X };
function obj_pattern2<X>({ prop }: Prop<X>) {} function obj_pattern2<X>({ prop }: Prop<X>) {}
// prop: X
function arr_pattern<X>([ elem ]: X[]) {} function arr_pattern<X>([ elem ]: X[]) {}
// elem: X
type Elem<X> = X[]; type Elem<X> = X[];
function arr_pattern2<X>([ elem ]: Elem<X>) {} function arr_pattern2<X>([ elem ]: Elem<X>) {}
// elem: X
function tup_pattern<X>([ proj ]: [X]) {} function tup_pattern<X>([ proj ]: [X]) {}
// proj: X
type Proj<X> = [X]; type Proj<X> = [X];
function tup_pattern2<X>([ proj ]: Proj<X>) {} function tup_pattern2<X>([ proj ]: Proj<X>) {}
// proj: X
function rest_antipattern<T>(...t: T) {} function rest_antipattern<T>(...t: T) {}
// nonsense
function rest_pattern<X>(...r: X[]) {} function rest_pattern<X>(...r: X[]) {}
// r: X[]
function obj_rest_pattern<X>({ _, ...o }: { _: any, x: X }) { function obj_rest_pattern<X>({ _, ...o }: { _: any, x: X }) {
// o: { x: X }
o.x; o.x;
} }
type ObjRest<X> = { _: any, x: X }; type ObjRest<X> = { _: any, x: X };
function obj_rest_pattern<X>({ _, ...o }: ObjRest<X>) { function obj_rest_pattern<X>({ _, ...o }: ObjRest<X>) {
// o: { x: X }
o.x; o.x;
} }
function arr_rest_pattern<X>([ _, ...a ]: [any, X]) { function arr_rest_pattern<X>([ _, ...a ]: [any, X]) {
// a: [X]
a[0]; a[0];
} }
type ArrRest<X> = [any, X]; type ArrRest<X> = [any, X];
function arr_rest_pattern<X>([ _, ...a ]: ArrRest<X>) { function arr_rest_pattern<X>([ _, ...a ]: ArrRest<X>) {
// a: [X]
a[0]; a[0];
} }"
"
`; `;
exports[`test rec.js 1`] = ` exports[`test rec.js 1`] = `
@ -500,20 +520,24 @@ declare var o;
var { x: o } = o; var { x: o } = o;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// Make sure that destructuring doesn\'t cause infinite loops when combined with // Make sure that destructuring doesn\'t cause infinite loops when combined with
// funny doses of repositioning // funny doses of repositioning
// Also make sure that the following doesn\'t loop
let foo = (i: number) => [ i ]; let foo = (i: number) => [ i ];
const bar = (i: number) => { const bar = (i: number) => {
[ i ] = foo(i); [ i ] = foo(i);
return [ i ]; return [ i ];
}; };
foo = (i: number) => { foo = (i: number) => {
return bar(i); return bar(i);
}; };
// Also make sure that the following doesn\'t loop
declare var o; declare var o;
var { x: o } = o; var { x: o } = o;"
"
`; `;
exports[`test string_lit.js 1`] = ` exports[`test string_lit.js 1`] = `
@ -523,13 +547,11 @@ exports[`test string_lit.js 1`] = `
var { \"with-dash\": with_dash } = { \"with-dash\": \"motivating example\" }; var { \"with-dash\": with_dash } = { \"with-dash\": \"motivating example\" };
(with_dash: \"motivating example\"); // ok (with_dash: \"motivating example\"); // ok
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: string ~> void
// ok
var { \"key\": val } = { key: \"val\" }; var { \"key\": val } = { key: \"val\" };
(val: void); (val: void);
// error: string ~> void
var { \"with-dash\": with_dash } = { \"with-dash\": \"motivating example\" }; var { \"with-dash\": with_dash } = { \"with-dash\": \"motivating example\" };
(with_dash: \"motivating example\"); (with_dash: \"motivating example\"); // ok"
"
`; `;
exports[`test unannotated.js 1`] = ` exports[`test unannotated.js 1`] = `
@ -544,9 +566,10 @@ function bar() {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
var { x } = { x: { foo: \"foo\" } }; var { x } = { x: { foo: \"foo\" } };
function bar() { function bar() {
x.bar; x.bar;
} }"
"
`; `;

View File

@ -6,11 +6,10 @@ const k: any = \'foo\'
const val: string = dict[k] // error: number incompatible with string const val: string = dict[k] // error: number incompatible with string
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error: number incompatible with string
const dict: { [key: string]: number } = {}; const dict: { [key: string]: number } = {};
const k: any = \"foo\"; const k: any = \"foo\";
const val: string = dict[k]; const val: string = dict[k]; // error: number incompatible with string"
"
`; `;
exports[`test compatible.js 1`] = ` exports[`test compatible.js 1`] = `
@ -31,21 +30,22 @@ function foo2(
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// this adds a fooBar property to the param type, which should NOT cause
// an error in the return type because it is a dictionary.
// x\'s prototype has a toString method
function foo0( function foo0(
x: Array<{ [key: string]: mixed }> x: Array<{ [key: string]: mixed }>
): Array<{ [key: string]: mixed }> { ): Array<{ [key: string]: mixed }> {
// this adds a fooBar property to the param type, which should NOT cause
// an error in the return type because it is a dictionary.
x[0].fooBar = \"foobar\"; x[0].fooBar = \"foobar\";
return x; return x;
} }
function foo2( function foo2(
x: { [key: string]: number } x: { [key: string]: number }
): { [key: string]: number, +toString: () => string } { ): { [key: string]: number, +toString: () => string } {
// x\'s prototype has a toString method
return x; return x;
} }"
"
`; `;
exports[`test dictionary.js 1`] = ` exports[`test dictionary.js 1`] = `
@ -385,288 +385,310 @@ function subtype_optional_c_to_dict(
* *
* @flow * @flow
*/ */
// Some logic is variance-sensitive. // Some logic is variance-sensitive.
class A {}
class B extends A {}
class C extends B {}
// Just a couple of short type names. Compare to string/number. // Just a couple of short type names. Compare to string/number.
class X {}
class Y {}
// Any property can be set on a dict with string keys. // Any property can be set on a dict with string keys.
function set_prop_to_string_key(o: { [k: string]: any }) {
o.prop = \"ok\";
}
// **UNSOUND** // **UNSOUND**
// This is allowed by design. We don\'t track get/set and we don\'t wrap the // This is allowed by design. We don\'t track get/set and we don\'t wrap the
// return type in a maybe. // return type in a maybe.
// ok function unsound_dict_has_every_key(o: { [k: string]: X }) {
// ok (o.p: X);
// ok
(o[\"p\"]: X); // ok
}
// As with any object type, we can assign subtypes to properties. // As with any object type, we can assign subtypes to properties.
// error, A ~> B function set_prop_covariant(o: { [k: string]: B }) {
// ok o.p = new A();
// ok // error, A ~> B
o.p = new B();
// ok
o.p = new C(); // ok
}
// This isn\'t specific behavior to dictionaries, but for completeness... // This isn\'t specific behavior to dictionaries, but for completeness...
// ok function get_prop_contravariant(o: { [k: string]: B }) {
// ok (o.p: A);
// error, C ~> B // ok
(o.p: B);
// ok
(o.p: C); // error, C ~> B
}
// Dot-notation can not be used to add properties to dictionaries with // Dot-notation can not be used to add properties to dictionaries with
// non-string keys, because keys are strings. // non-string keys, because keys are strings.
// error: string ~> number function add_prop_to_nonstring_key_dot(o: { [k: number]: any }) {
o.prop = \"err\"; // error: string ~> number
}
// Bracket notation can be used to add properties to dictionaries with // Bracket notation can be used to add properties to dictionaries with
// non-string keys, even though all keys are strings. This is a convenient // non-string keys, even though all keys are strings. This is a convenient
// affordance. // affordance.
function add_prop_to_nonstring_key_bracket(o: { [k: number]: any }) {
o[0] = \"ok\";
}
// Objects can be part dict, part not by mixing an indexer with declared props. // Objects can be part dict, part not by mixing an indexer with declared props.
// ok function mix_with_declared_props(o: { [k: number]: X, p: Y }, x: X, y: Y) {
// ok (o[0]: X);
// ok // ok
// ok (o.p: Y);
// ok
o[0] = x;
// ok
o.p = y; // ok
}
// Indeed, dict types are still Objects and have Object.prototype stuff // Indeed, dict types are still Objects and have Object.prototype stuff
// error: string ~> boolean function object_prototype(
// ok o: { [k: string]: number }
): { [k: string]: number, +toString: () => string } {
(o.toString(): boolean);
// error: string ~> boolean
return o; // ok
}
// **UNSOUND** // **UNSOUND**
// Because we support non-string props w/ bracket notation, it\'s possible to // Because we support non-string props w/ bracket notation, it\'s possible to
// write into a declared prop unsoundly. // write into a declared prop unsoundly.
// a[\"0\"] no longer X function unsound_string_conversion_alias_declared_prop(
// error o: { [k: number]: any, \"0\": X }
// in[0].p no longer B ) {
// ok o[0] = \"not-x\"; // a[\"0\"] no longer X
// error }
// not true
// error function unification_dict_values_invariant(x: Array<{ [k: string]: B }>) {
// x[0].p no longer B let a: Array<{ [k: string]: A }> = x;
// ok // error
// error a[0].p = new A();
// not true // in[0].p no longer B
// ok, A == A let b: Array<{ [k: string]: B }> = x;
// ok, B <: A // ok
// ok, C <: A let c: Array<{ [k: string]: C }> = x;
// error, A not <: B // error
// ok, B == B (x[0].p: C); // not true
// ok, C <: A }
// error, A not <: C
// error, A not <: C function subtype_dict_values_invariant(x: { [k: string]: B }) {
// ok, C == C let a: { [k: string]: A } = x;
// error
a.p = new A();
// x[0].p no longer B
let b: { [k: string]: B } = x;
// ok
let c: { [k: string]: C } = x;
// error
(x.p: C); // not true
}
function subtype_dict_values_fresh_exception() {
let a: { [k: string]: A } = {
a: new A(),
// ok, A == A
b: new B(),
// ok, B <: A
// ok, C <: A
c: new C()
};
let b: { [k: string]: B } = {
a: new A(),
// error, A not <: B
b: new B(),
// ok, B == B
// ok, C <: A
c: new C()
};
let c: { [k: string]: C } = {
a: new A(),
// error, A not <: C
b: new B(),
// error, A not <: C
// ok, C == C
c: new C()
};
}
// Actually, unsound_string_conversion_alias_declared_prop behavior makes an // Actually, unsound_string_conversion_alias_declared_prop behavior makes an
// argument that we shouldn\'t really care about this, since we ignore the fact // argument that we shouldn\'t really care about this, since we ignore the fact
// that coercing values to string keys can cause unintended aliasing in general. // that coercing values to string keys can cause unintended aliasing in general.
// Barring some compelling use case for that in this context, though, we choose // Barring some compelling use case for that in this context, though, we choose
// to be strict. // to be strict.
// error
// ok
// error
// error
// ok
// error
// error: A ~> B
// x[0].p no longer B
// ok
// error
// not true
// error
// xa[0].p no longer B
// ok
// error
// not true
// error: A ~> B
// x.p no longer B
// ok
// error
// not true
// error
// xa.p no longer B
// ok
// error
// not true
// error: if allowed, could write {p:X,q:Y} into \`x\`
// error: if allowed, could write {p:X,q:Y} into returned array
// error
// x.p no longer B
// ok
// error
// not true
// error
// x.p no longer B
// error
// not true
// Only props in l which are not in u must match indexer, but must do so
// exactly.
// error (as above), but exclusive of x
// ok,
// error (as above), but exclusive of x
// error
// ok
// error
// error
// ok
// error
// error
// ok
// error
// error: A ~> B
// ok
// error: C ~> B
class A {}
class B extends A {}
class C extends B {}
class X {}
class Y {}
function set_prop_to_string_key(o: { [k: string]: any }) {
o.prop = \"ok\";
}
function unsound_dict_has_every_key(o: { [k: string]: X }) {
(o.p: X);
(o[\"p\"]: X);
}
function set_prop_covariant(o: { [k: string]: B }) {
o.p = new A();
o.p = new B();
o.p = new C();
}
function get_prop_contravariant(o: { [k: string]: B }) {
(o.p: A);
(o.p: B);
(o.p: C);
}
function add_prop_to_nonstring_key_dot(o: { [k: number]: any }) {
o.prop = \"err\";
}
function add_prop_to_nonstring_key_bracket(o: { [k: number]: any }) {
o[0] = \"ok\";
}
function mix_with_declared_props(o: { [k: number]: X, p: Y }, x: X, y: Y) {
(o[0]: X);
(o.p: Y);
o[0] = x;
o.p = y;
}
function object_prototype(
o: { [k: string]: number }
): { [k: string]: number, +toString: () => string } {
(o.toString(): boolean);
return o;
}
function unsound_string_conversion_alias_declared_prop(
o: { [k: number]: any, \"0\": X }
) {
o[0] = \"not-x\";
}
function unification_dict_values_invariant(x: Array<{ [k: string]: B }>) {
let a: Array<{ [k: string]: A }> = x;
a[0].p = new A();
let b: Array<{ [k: string]: B }> = x;
let c: Array<{ [k: string]: C }> = x;
(x[0].p: C);
}
function subtype_dict_values_invariant(x: { [k: string]: B }) {
let a: { [k: string]: A } = x;
a.p = new A();
let b: { [k: string]: B } = x;
let c: { [k: string]: C } = x;
(x.p: C);
}
function subtype_dict_values_fresh_exception() {
let a: { [k: string]: A } = { a: new A(), b: new B(), c: new C() };
let b: { [k: string]: B } = { a: new A(), b: new B(), c: new C() };
let c: { [k: string]: C } = { a: new A(), b: new B(), c: new C() };
}
function unification_dict_keys_invariant(x: Array<{ [k: B]: any }>) { function unification_dict_keys_invariant(x: Array<{ [k: B]: any }>) {
let a: Array<{ [k: A]: any }> = x; let a: Array<{ [k: A]: any }> = x;
// error
let b: Array<{ [k: B]: any }> = x; let b: Array<{ [k: B]: any }> = x;
let c: Array<{ [k: C]: any }> = x; // ok
let c: Array<{ [k: C]: any }> = x; // error
} }
function subtype_dict_keys_invariant(x: { [k: B]: any }) { function subtype_dict_keys_invariant(x: { [k: B]: any }) {
let a: { [k: A]: any } = x; let a: { [k: A]: any } = x;
// error
let b: { [k: B]: any } = x; let b: { [k: B]: any } = x;
let c: { [k: C]: any } = x; // ok
let c: { [k: C]: any } = x; // error
} }
function unification_mix_with_declared_props_invariant_l( function unification_mix_with_declared_props_invariant_l(
x: Array<{ [k: string]: B }> x: Array<{ [k: string]: B }>
) { ) {
let a: Array<{ [k: string]: B, p: A }> = x; let a: Array<{ [k: string]: B, p: A }> = x;
// error: A ~> B
a[0].p = new A(); a[0].p = new A();
// x[0].p no longer B
let b: Array<{ [k: string]: B, p: B }> = x; let b: Array<{ [k: string]: B, p: B }> = x;
// ok
let c: Array<{ [k: string]: B, p: C }> = x; let c: Array<{ [k: string]: B, p: C }> = x;
(x[0].p: C); // error
(x[0].p: C); // not true
} }
function unification_mix_with_declared_props_invariant_r( function unification_mix_with_declared_props_invariant_r(
xa: Array<{ [k: string]: A, p: B }>, xa: Array<{ [k: string]: A, p: B }>,
xb: Array<{ [k: string]: B, p: B }>, xb: Array<{ [k: string]: B, p: B }>,
xc: Array<{ [k: string]: C, p: B }> xc: Array<{ [k: string]: C, p: B }>
) { ) {
let a: Array<{ [k: string]: A }> = xa; let a: Array<{ [k: string]: A }> = xa;
// error
a[0].p = new A(); a[0].p = new A();
// xa[0].p no longer B
let b: Array<{ [k: string]: B }> = xb; let b: Array<{ [k: string]: B }> = xb;
// ok
let c: Array<{ [k: string]: C }> = xc; let c: Array<{ [k: string]: C }> = xc;
(xc[0].p: C); // error
(xc[0].p: C); // not true
} }
function subtype_mix_with_declared_props_invariant_l(x: { [k: string]: B }) { function subtype_mix_with_declared_props_invariant_l(x: { [k: string]: B }) {
let a: { [k: string]: B, p: A } = x; let a: { [k: string]: B, p: A } = x;
// error: A ~> B
a.p = new A(); a.p = new A();
// x.p no longer B
let b: { [k: string]: B, p: B } = x; let b: { [k: string]: B, p: B } = x;
// ok
let c: { [k: string]: B, p: C } = x; let c: { [k: string]: B, p: C } = x;
(x.p: C); // error
(x.p: C); // not true
} }
function subtype_mix_with_declared_props_invariant_r( function subtype_mix_with_declared_props_invariant_r(
xa: { [k: string]: A, p: B }, xa: { [k: string]: A, p: B },
xb: { [k: string]: B, p: B }, xb: { [k: string]: B, p: B },
xc: { [k: string]: C, p: B } xc: { [k: string]: C, p: B }
) { ) {
let a: { [k: string]: A } = xa; let a: { [k: string]: A } = xa;
// error
a.p = new A(); a.p = new A();
// xa.p no longer B
let b: { [k: string]: B } = xb; let b: { [k: string]: B } = xb;
// ok
let c: { [k: string]: C } = xc; let c: { [k: string]: C } = xc;
(xc.p: C); // error
(xc.p: C); // not true
} }
function unification_dict_to_obj( function unification_dict_to_obj(
x: Array<{ [k: string]: X }> x: Array<{ [k: string]: X }>
): Array<{ p: X }> { ): Array<{ p: X }> {
return x; return x; // error: if allowed, could write {p:X,q:Y} into \`x\`
} }
function unification_obj_to_dict( function unification_obj_to_dict(
x: Array<{ p: X }> x: Array<{ p: X }>
): Array<{ [k: string]: X }> { ): Array<{ [k: string]: X }> {
return x; return x; // error: if allowed, could write {p:X,q:Y} into returned array
} }
function subtype_dict_to_obj(x: { [k: string]: B }) { function subtype_dict_to_obj(x: { [k: string]: B }) {
let a: { p: A } = x; let a: { p: A } = x;
// error
a.p = new A(); a.p = new A();
// x.p no longer B
let b: { p: B } = x; let b: { p: B } = x;
// ok
let c: { p: C } = x; let c: { p: C } = x;
(x.p: C); // error
(x.p: C); // not true
} }
function subtype_obj_to_dict(x: { p: B }) { function subtype_obj_to_dict(x: { p: B }) {
let a: { [k: string]: A } = x; let a: { [k: string]: A } = x;
// error
a.p = new A(); a.p = new A();
// x.p no longer B
let b: { [k: string]: B } = x; let b: { [k: string]: B } = x;
let c: { [k: string]: C } = x; let c: { [k: string]: C } = x;
(x.p: C); // error
(x.p: C); // not true
} }
// Only props in l which are not in u must match indexer, but must do so
// exactly.
function subtype_obj_to_mixed(x: { p: B, x: X }) { function subtype_obj_to_mixed(x: { p: B, x: X }) {
let a: { [k: string]: A, x: X } = x; let a: { [k: string]: A, x: X } = x;
// error (as above), but exclusive of x
let b: { [k: string]: B, x: X } = x; let b: { [k: string]: B, x: X } = x;
let c: { [k: string]: C, x: X } = x; // ok,
let c: { [k: string]: C, x: X } = x; // error (as above), but exclusive of x
} }
function unification_dict_to_mixed(x: Array<{ [k: string]: B }>) { function unification_dict_to_mixed(x: Array<{ [k: string]: B }>) {
let a: Array<{ [k: string]: B, p: A }> = x; let a: Array<{ [k: string]: B, p: A }> = x;
// error
let b: Array<{ [k: string]: B, p: B }> = x; let b: Array<{ [k: string]: B, p: B }> = x;
let c: Array<{ [k: string]: B, p: C }> = x; // ok
let c: Array<{ [k: string]: B, p: C }> = x; // error
} }
function subtype_dict_to_mixed(x: { [k: string]: B }) { function subtype_dict_to_mixed(x: { [k: string]: B }) {
let a: { [k: string]: B, p: A } = x; let a: { [k: string]: B, p: A } = x;
// error
let b: { [k: string]: B, p: B } = x; let b: { [k: string]: B, p: B } = x;
let c: { [k: string]: B, p: C } = x; // ok
let c: { [k: string]: B, p: C } = x; // error
} }
function subtype_dict_to_optional_a(x: { [k: string]: B }) { function subtype_dict_to_optional_a(x: { [k: string]: B }) {
let a: { p?: A } = x; let a: { p?: A } = x; // error
} }
function subtype_dict_to_optional_b(x: { [k: string]: B }) { function subtype_dict_to_optional_b(x: { [k: string]: B }) {
let b: { p?: B } = x; let b: { p?: B } = x; // ok
} }
function subtype_dict_to_optional_c(x: { [k: string]: B }) { function subtype_dict_to_optional_c(x: { [k: string]: B }) {
let c: { p?: C } = x; let c: { p?: C } = x; // error
} }
function subtype_optional_a_to_dict(x: { p?: A }): { [k: string]: B } { function subtype_optional_a_to_dict(x: { p?: A }): { [k: string]: B } {
// error: A ~> B
return x; return x;
} }
function subtype_optional_b_to_dict(x: { p?: B }): { [k: string]: B } { function subtype_optional_b_to_dict(x: { p?: B }): { [k: string]: B } {
// ok
return x; return x;
} }
function subtype_optional_c_to_dict(x: { p?: C }): { [k: string]: B } { function subtype_optional_c_to_dict(x: { p?: C }): { [k: string]: B } {
// error: C ~> B
return x; return x;
} }"
"
`; `;
exports[`test incompatible.js 1`] = ` exports[`test incompatible.js 1`] = `
@ -729,63 +751,70 @@ function foo8(x: {[key: string]: number}) {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// 2 errors, number !~> string & vice versa
// 2 errors, string !~> number & vice versa
// 2 errors (null & undefined)
// 2 errors, since c[\'x\'] = null updates b
// 2 errors (number !~> string, string !~> number)
// error, fooBar:string !~> number (x\'s dictionary)
// OK, since number ~> mixed (x elem\'s dictionary)
// error: mixed ~> string
// OK, since we assume dictionaries have every key
// error: foo can\'t exist in x
// error, some prop in x could be incompatible (covariance)
// error, some prop in return could be incompatible
// error
var x: { [key: string]: string } = {}; var x: { [key: string]: string } = {};
var y: { [key: string]: number } = x; var y: { [key: string]: number } = x;
// 2 errors, number !~> string & vice versa
var z: { [key: number]: string } = x; var z: { [key: number]: string } = x;
// 2 errors, string !~> number & vice versa
var a: { [key: string]: ?string } = {}; var a: { [key: string]: ?string } = {};
var b: { [key: string]: string } = a; var b: { [key: string]: string } = a;
// 2 errors (null & undefined)
var c: { [key: string]: ?string } = b; var c: { [key: string]: ?string } = b;
// 2 errors, since c[\'x\'] = null updates b
// 2 errors (number !~> string, string !~> number)
function foo0( function foo0(
x: Array<{ [key: string]: number }> x: Array<{ [key: string]: number }>
): Array<{ [key: string]: string }> { ): Array<{ [key: string]: string }> {
return x; return x;
} }
// error, fooBar:string !~> number (x\'s dictionary)
function foo1( function foo1(
x: Array<{ [key: string]: number }> x: Array<{ [key: string]: number }>
): Array<{ [key: string]: number, fooBar: string }> { ): Array<{ [key: string]: number, fooBar: string }> {
return x; return x;
} }
function foo2( function foo2(
x: Array<{ [key: string]: mixed }> x: Array<{ [key: string]: mixed }>
): Array<{ [key: string]: mixed, fooBar: string }> { ): Array<{ [key: string]: mixed, fooBar: string }> {
x[0].fooBar = 123; x[0].fooBar = 123;
return x; // OK, since number ~> mixed (x elem\'s dictionary)
return x; // error: mixed ~> string
} }
// OK, since we assume dictionaries have every key
function foo3(x: { [key: string]: number }): { foo: number } { function foo3(x: { [key: string]: number }): { foo: number } {
return x; return x;
} }
// error: foo can\'t exist in x
function foo4( function foo4(
x: { [key: string]: number } x: { [key: string]: number }
): { [key: string]: number, foo: string } { ): { [key: string]: number, foo: string } {
return x; return x;
} }
// error, some prop in x could be incompatible (covariance)
function foo5(x: Array<{ [key: string]: number }>): Array<{ foo: number }> { function foo5(x: Array<{ [key: string]: number }>): Array<{ foo: number }> {
return x; return x;
} }
// error, some prop in return could be incompatible
function foo6(x: Array<{ foo: number }>): Array<{ [key: string]: number }> { function foo6(x: Array<{ foo: number }>): Array<{ [key: string]: number }> {
return x; return x;
} }
function foo7(x: { [key: string]: number, bar: string }) { function foo7(x: { [key: string]: number, bar: string }) {
(x.bar: string); (x.bar: string);
} }
function foo8(x: { [key: string]: number }) { function foo8(x: { [key: string]: number }) {
(x.foo: string); (x.foo: string);
// error
(x.foo: number); (x.foo: number);
} }"
"
`; `;
exports[`test issue-1745.js 1`] = ` exports[`test issue-1745.js 1`] = `
@ -816,29 +845,30 @@ class B {
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// no error
// no error
// no error
// no error
class A { class A {
x: { [k: string]: number }; x: { [k: string]: number };
m1() { m1() {
this.x = { bar: 0 }; this.x = { bar: 0 }; // no error
} }
m2() { m2() {
this.x.foo = 0; this.x.foo = 0; // no error
} }
} }
class B { class B {
x: { [k: string]: number }; x: { [k: string]: number };
m2() { m2() {
this.x.foo = 0; this.x.foo = 0; // no error
} }
m1() { m1() {
this.x = { bar: 0 }; this.x = { bar: 0 }; // no error
} }
} }"
"
`; `;
exports[`test test.js 1`] = ` exports[`test test.js 1`] = `
@ -853,16 +883,16 @@ var o: { foo: QueryFunction } = {
module.exports = o; module.exports = o;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, number ~/~ string
type Params = { [name: string]: string, count: number }; type Params = { [name: string]: string, count: number };
type QueryFunction = (params: Params) => string; type QueryFunction = (params: Params) => string;
var o: { foo: QueryFunction } = { var o: { foo: QueryFunction } = {
foo(params) { foo(params) {
return params.count; return params.count; // error, number ~/~ string
} }
}; };
module.exports = o;
" module.exports = o;"
`; `;
exports[`test test_client.js 1`] = ` exports[`test test_client.js 1`] = `
@ -872,10 +902,9 @@ o.foo = function (params) {
return params.count; // error, number ~/~ string return params.count; // error, number ~/~ string
} }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error, number ~/~ string
var o = require(\"./test\"); var o = require(\"./test\");
o.foo = function(params) { o.foo = function(params) {
return params.count; return params.count; // error, number ~/~ string
}; };"
"
`; `;

View File

@ -83,6 +83,7 @@ export type TypedNode =
/** /**
* @flow * @flow
*/ */
export type InferredType = \"unknown\" | export type InferredType = \"unknown\" |
\"gender\" | \"gender\" |
\"enum\" | \"enum\" |
@ -90,12 +91,14 @@ export type InferredType = \"unknown\" |
\"number\" | \"number\" |
\"string\" | \"string\" |
\"error\"; \"error\";
export type Pos = { export type Pos = {
firstLine: number, firstLine: number,
firstColumn: number, firstColumn: number,
lastLine: number, lastLine: number,
lastColumn: number lastColumn: number
}; };
export type TypedBinaryOpNode = { export type TypedBinaryOpNode = {
exprNodeType: \"binary_op\", exprNodeType: \"binary_op\",
binaryOp: \"plus\" | \"multiply\" | \"divide\" | \"minus\", binaryOp: \"plus\" | \"multiply\" | \"divide\" | \"minus\",
@ -105,6 +108,7 @@ export type TypedBinaryOpNode = {
exprType: InferredType, exprType: InferredType,
typed: true typed: true
}; };
export type TypedUnaryMinusNode = { export type TypedUnaryMinusNode = {
exprNodeType: \"unary_minus\", exprNodeType: \"unary_minus\",
op: TypedNode, op: TypedNode,
@ -112,6 +116,7 @@ export type TypedUnaryMinusNode = {
exprType: InferredType, exprType: InferredType,
typed: true typed: true
}; };
export type TypedNumberNode = { export type TypedNumberNode = {
exprNodeType: \"number\", exprNodeType: \"number\",
value: number, value: number,
@ -119,6 +124,7 @@ export type TypedNumberNode = {
exprType: \"number\", exprType: \"number\",
typed: true typed: true
}; };
export type TypedStringLiteralNode = { export type TypedStringLiteralNode = {
exprNodeType: \"string_literal\", exprNodeType: \"string_literal\",
value: string, value: string,
@ -126,6 +132,7 @@ export type TypedStringLiteralNode = {
exprType: \"string\", exprType: \"string\",
typed: true typed: true
}; };
export type TypedVariableNode = { export type TypedVariableNode = {
exprNodeType: \"variable\", exprNodeType: \"variable\",
name: string, name: string,
@ -133,6 +140,7 @@ export type TypedVariableNode = {
exprType: InferredType, exprType: InferredType,
typed: true typed: true
}; };
export type TypedFunctionInvocationNode = { export type TypedFunctionInvocationNode = {
exprNodeType: \"function_invocation\", exprNodeType: \"function_invocation\",
name: string, name: string,
@ -141,13 +149,13 @@ export type TypedFunctionInvocationNode = {
exprType: \"error\" | \"string\", exprType: \"error\" | \"string\",
typed: true typed: true
}; };
export type TypedNode = TypedBinaryOpNode | export type TypedNode = TypedBinaryOpNode |
TypedUnaryMinusNode | TypedUnaryMinusNode |
TypedNumberNode | TypedNumberNode |
TypedStringLiteralNode | TypedStringLiteralNode |
TypedVariableNode | TypedVariableNode |
TypedFunctionInvocationNode; TypedFunctionInvocationNode;"
"
`; `;
exports[`test emit.js 1`] = ` exports[`test emit.js 1`] = `
@ -220,10 +228,12 @@ export function emitExpression(node: TypedNode) : t.Expression {
/** /**
* @flow * @flow
*/ */
// FALLTHROUGH
import * as t from \"./jsAst\"; import * as t from \"./jsAst\";
const b = t.builders; const b = t.builders;
import type {TypedNode} from \"./ast\"; import type {TypedNode} from \"./ast\";
function getBinaryOp( function getBinaryOp(
op: \"plus\" | \"minus\" | \"divide\" | \"multiply\" op: \"plus\" | \"minus\" | \"divide\" | \"multiply\"
): \"+\" | \"-\" | \"*\" | \"/\" { ): \"+\" | \"-\" | \"*\" | \"/\" {
@ -240,9 +250,11 @@ function getBinaryOp(
throw new Error(\"Invalid binary operator: \" + op); throw new Error(\"Invalid binary operator: \" + op);
} }
} }
export function emitExpression(node: TypedNode): t.Expression { export function emitExpression(node: TypedNode): t.Expression {
switch (node.exprNodeType) { switch (node.exprNodeType) {
case \"string_literal\": case \"string_literal\":
// FALLTHROUGH
case \"number\": case \"number\":
return b.literal(node.value); return b.literal(node.value);
case \"variable\": case \"variable\":
@ -254,6 +266,7 @@ export function emitExpression(node: TypedNode): t.Expression {
case \"binary_op\": { case \"binary_op\": {
const lhs = emitExpression(node.lhs); const lhs = emitExpression(node.lhs);
const rhs = emitExpression(node.rhs); const rhs = emitExpression(node.rhs);
const op = getBinaryOp(node.binaryOp); const op = getBinaryOp(node.binaryOp);
return b.binaryExpression(op, lhs, rhs); return b.binaryExpression(op, lhs, rhs);
} }
@ -267,14 +280,15 @@ export function emitExpression(node: TypedNode): t.Expression {
b.identifier(node.name), b.identifier(node.name),
false false
); );
const args = node.parameters.map(n => emitExpression(n)); const args = node.parameters.map(n => emitExpression(n));
return b.callExpression(callee, args); return b.callExpression(callee, args);
} }
default: default:
throw new Error(\"Unknown expression type: \" + node.type); throw new Error(\"Unknown expression type: \" + node.type);
} }
} }"
"
`; `;
exports[`test jsAst.js 1`] = ` exports[`test jsAst.js 1`] = `
@ -918,21 +932,21 @@ export const builders : {
/** /**
* @flow * @flow
*/ */
/* TODO Missing from the Parser API.*/
// ast-types exports all expressions as patterns.
// That seems not like it was intended.
export type Comment = { export type Comment = {
loc: ?SourceLocation, loc: ?SourceLocation,
value: string, value: string,
leading: boolean, leading: boolean,
trailing: boolean trailing: boolean
}; };
export type SourceLocation = { export type SourceLocation = {
start: SourcePosition, start: SourcePosition,
end: SourcePosition, end: SourcePosition,
source: ?string source: ?string
}; };
export type SourcePosition = { line: number, column: number }; export type SourcePosition = { line: number, column: number };
export type File = { export type File = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -941,6 +955,7 @@ export type File = {
type: \"File\", type: \"File\",
program: Program program: Program
}; };
export type Program = { export type Program = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -949,6 +964,7 @@ export type Program = {
type: \"Program\", type: \"Program\",
body: Statement[] body: Statement[]
}; };
export type BinaryOperator = \"==\" | export type BinaryOperator = \"==\" |
\"!=\" | \"!=\" |
\"===\" | \"===\" |
@ -965,12 +981,13 @@ export type BinaryOperator = \"==\" |
\"*\" | \"*\" |
\"/\" | \"/\" |
\"%\" | \"%\" |
\"&\" | \"&\" /* TODO Missing from the Parser API.*/ |
\"|\" | \"|\" |
\"^\" | \"^\" |
\"in\" | \"in\" |
\"instanceof\" | \"instanceof\" |
\"..\"; \"..\";
export type UnaryOperator = \"-\" | export type UnaryOperator = \"-\" |
\"+\" | \"+\" |
\"!\" | \"!\" |
@ -978,6 +995,7 @@ export type UnaryOperator = \"-\" |
\"typeof\" | \"typeof\" |
\"void\" | \"void\" |
\"delete\"; \"delete\";
export type AssignmentOperator = \"=\" | export type AssignmentOperator = \"=\" |
\"+=\" | \"+=\" |
\"-=\" | \"-=\" |
@ -990,8 +1008,11 @@ export type AssignmentOperator = \"=\" |
\"|=\" | \"|=\" |
\"^=\" | \"^=\" |
\"&=\"; \"&=\";
export type UpdateOperator = \"++\" | \"--\"; export type UpdateOperator = \"++\" | \"--\";
export type LogicalOperator = \"&&\" | \"||\"; export type LogicalOperator = \"&&\" | \"||\";
export type Node = EmptyStatement | export type Node = EmptyStatement |
BlockStatement | BlockStatement |
ExpressionStatement | ExpressionStatement |
@ -1024,6 +1045,7 @@ export type Node = EmptyStatement |
VariableDeclaration | VariableDeclaration |
FunctionDeclaration | FunctionDeclaration |
VariableDeclarator; VariableDeclarator;
export type Statement = BlockStatement | export type Statement = BlockStatement |
EmptyStatement | EmptyStatement |
ExpressionStatement | ExpressionStatement |
@ -1037,6 +1059,7 @@ export type Statement = BlockStatement |
ForInStatement | ForInStatement |
TryStatement | TryStatement |
Declaration; Declaration;
export type EmptyStatement = { export type EmptyStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1044,6 +1067,7 @@ export type EmptyStatement = {
comments: ?Array<Comment>, comments: ?Array<Comment>,
type: \"EmptyStatement\" type: \"EmptyStatement\"
}; };
export type BlockStatement = { export type BlockStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1052,6 +1076,7 @@ export type BlockStatement = {
type: \"BlockStatement\", type: \"BlockStatement\",
body: Statement[] body: Statement[]
}; };
export type ExpressionStatement = { export type ExpressionStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1060,6 +1085,7 @@ export type ExpressionStatement = {
type: \"ExpressionStatement\", type: \"ExpressionStatement\",
expression: Expression expression: Expression
}; };
export type IfStatement = { export type IfStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1070,6 +1096,7 @@ export type IfStatement = {
consequent: Statement, consequent: Statement,
alternate: ?Statement alternate: ?Statement
}; };
export type BreakStatement = { export type BreakStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1078,6 +1105,7 @@ export type BreakStatement = {
type: \"BreakStatement\", type: \"BreakStatement\",
label: ?Identifier label: ?Identifier
}; };
export type ContinueStatement = { export type ContinueStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1086,6 +1114,7 @@ export type ContinueStatement = {
type: \"ContinueStatement\", type: \"ContinueStatement\",
label: ?Identifier label: ?Identifier
}; };
export type ReturnStatement = { export type ReturnStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1094,6 +1123,7 @@ export type ReturnStatement = {
type: \"ReturnStatement\", type: \"ReturnStatement\",
argument: ?Expression argument: ?Expression
}; };
export type ThrowStatement = { export type ThrowStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1102,6 +1132,7 @@ export type ThrowStatement = {
type: \"ThrowStatement\", type: \"ThrowStatement\",
argument: ?Expression argument: ?Expression
}; };
export type WhileStatement = { export type WhileStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1111,6 +1142,7 @@ export type WhileStatement = {
test: Expression, test: Expression,
body: Statement body: Statement
}; };
export type ForStatement = { export type ForStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1122,6 +1154,7 @@ export type ForStatement = {
update: ?Expression, update: ?Expression,
body: Statement body: Statement
}; };
export type ForInStatement = { export type ForInStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1132,6 +1165,7 @@ export type ForInStatement = {
right: Expression, right: Expression,
body: Statement body: Statement
}; };
export type TryStatement = { export type TryStatement = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1143,6 +1177,7 @@ export type TryStatement = {
handlers: CatchClause[], handlers: CatchClause[],
finalizer: ?BlockStatement finalizer: ?BlockStatement
}; };
export type CatchClause = { export type CatchClause = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1153,6 +1188,7 @@ export type CatchClause = {
guard: ?Expression, guard: ?Expression,
body: BlockStatement body: BlockStatement
}; };
export type Expression = Identifier | export type Expression = Identifier |
ThisExpression | ThisExpression |
Literal | Literal |
@ -1168,6 +1204,7 @@ export type Expression = Identifier |
MemberExpression | MemberExpression |
ArrayExpression | ArrayExpression |
ObjectExpreession; ObjectExpreession;
export type Identifier = { export type Identifier = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1176,6 +1213,7 @@ export type Identifier = {
type: \"Identifier\", type: \"Identifier\",
name: string name: string
}; };
export type Literal = { export type Literal = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1185,6 +1223,7 @@ export type Literal = {
value: ?(string | boolean | number | RegExp), value: ?(string | boolean | number | RegExp),
regex: ?{ pattern: string, flags: string } regex: ?{ pattern: string, flags: string }
}; };
export type ThisExpression = { export type ThisExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1192,6 +1231,7 @@ export type ThisExpression = {
comments: ?Array<Comment>, comments: ?Array<Comment>,
type: \"ThisExpression\" type: \"ThisExpression\"
}; };
export type ArrayExpression = { export type ArrayExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1200,6 +1240,7 @@ export type ArrayExpression = {
type: \"ArrayExpression\", type: \"ArrayExpression\",
elements: Expression[] elements: Expression[]
}; };
export type ObjectExpreession = { export type ObjectExpreession = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1208,6 +1249,7 @@ export type ObjectExpreession = {
type: \"ObjectExpression\", type: \"ObjectExpression\",
properties: Property[] properties: Property[]
}; };
export type Property = { export type Property = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1218,6 +1260,7 @@ export type Property = {
key: Literal | Identifier, key: Literal | Identifier,
value: Expression value: Expression
}; };
export type FunctionExpression = { export type FunctionExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1228,6 +1271,7 @@ export type FunctionExpression = {
params: Pattern[], params: Pattern[],
body: BlockStatement body: BlockStatement
}; };
export type BinaryExpression = { export type BinaryExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1238,6 +1282,7 @@ export type BinaryExpression = {
left: Expression, left: Expression,
right: Expression right: Expression
}; };
export type UnaryExpression = { export type UnaryExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1248,6 +1293,7 @@ export type UnaryExpression = {
argument: Expression, argument: Expression,
prefix: boolean prefix: boolean
}; };
export type AssignmentExpression = { export type AssignmentExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1258,6 +1304,7 @@ export type AssignmentExpression = {
left: Pattern, left: Pattern,
right: Expression right: Expression
}; };
export type UpdateExpression = { export type UpdateExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1268,6 +1315,7 @@ export type UpdateExpression = {
argument: Expression, argument: Expression,
prefix: boolean prefix: boolean
}; };
export type LogicalExpression = { export type LogicalExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1278,6 +1326,7 @@ export type LogicalExpression = {
left: Expression, left: Expression,
right: Expression right: Expression
}; };
export type ConditionalExpression = { export type ConditionalExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1288,6 +1337,7 @@ export type ConditionalExpression = {
consequent: Expression, consequent: Expression,
alternate: Expression alternate: Expression
}; };
export type NewExpression = { export type NewExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1297,6 +1347,7 @@ export type NewExpression = {
callee: Expression, callee: Expression,
arguments: Expression[] arguments: Expression[]
}; };
export type CallExpression = { export type CallExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1306,6 +1357,7 @@ export type CallExpression = {
callee: Expression, callee: Expression,
arguments: Expression[] arguments: Expression[]
}; };
export type MemberExpression = { export type MemberExpression = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1316,8 +1368,12 @@ export type MemberExpression = {
property: Identifier | Expression, property: Identifier | Expression,
computed: boolean computed: boolean
}; };
// ast-types exports all expressions as patterns.
// That seems not like it was intended.
export type Pattern = Identifier; export type Pattern = Identifier;
export type Declaration = VariableDeclaration | FunctionDeclaration; export type Declaration = VariableDeclaration | FunctionDeclaration;
export type VariableDeclaration = { export type VariableDeclaration = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1327,6 +1383,7 @@ export type VariableDeclaration = {
kind: \"var\" | \"let\" | \"const\", kind: \"var\" | \"let\" | \"const\",
declarations: VariableDeclarator[] declarations: VariableDeclarator[]
}; };
export type FunctionDeclaration = { export type FunctionDeclaration = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1337,6 +1394,7 @@ export type FunctionDeclaration = {
body: BlockStatement, body: BlockStatement,
params: Pattern[] params: Pattern[]
}; };
export type VariableDeclarator = { export type VariableDeclarator = {
source: ?string, source: ?string,
start: SourcePosition, start: SourcePosition,
@ -1346,7 +1404,9 @@ export type VariableDeclarator = {
id: Pattern, id: Pattern,
init: ?Expression init: ?Expression
}; };
const a: any = null; const a: any = null;
export const builders: { export const builders: {
emptyStatement(): EmptyStatement, emptyStatement(): EmptyStatement,
blockStatement(body: Statement[]): BlockStatement, blockStatement(body: Statement[]): BlockStatement,
@ -1448,6 +1508,5 @@ export const builders: {
params: Pattern[] params: Pattern[]
): FunctionDeclaration, ): FunctionDeclaration,
variableDeclarator(id: Pattern, init?: Expression): VariableDeclarator variableDeclarator(id: Pattern, init?: Expression): VariableDeclarator
} = a; } = a;"
"
`; `;

View File

@ -6,9 +6,8 @@ exports[`test license_with_flow.js 1`] = `
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* Copyright example */ /* Copyright example */
/* @flow */ /* @flow */
// error
(\"\": void); (\"\": void); // error"
"
`; `;
exports[`test max_header_tokens.js 1`] = ` exports[`test max_header_tokens.js 1`] = `
@ -21,15 +20,6 @@ exports[`test max_header_tokens.js 1`] = `
* @flow * @flow
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
/* second token */
/* third token */
/**
* After max_header_tokens (in .flowconfig), we no longer care:
*
* @flow
*/
" "
`; `;
@ -37,9 +27,6 @@ exports[`test multiple_flows_1.js 1`] = `
"/* @flow */ "/* @flow */
/* @flow */ /* @flow */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
/* @flow */
" "
`; `;
@ -49,11 +36,6 @@ exports[`test multiple_flows_2.js 1`] = `
* @noflow * @noflow
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @flow
* @noflow
*/
" "
`; `;
@ -64,12 +46,6 @@ exports[`test multiple_providesModule_1.js 1`] = `
* @flow * @flow
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @providesModule Foo
* @providesModule Bar
* @flow
*/
" "
`; `;
@ -82,14 +58,6 @@ exports[`test multiple_providesModule_2.js 1`] = `
* @providesModule Bar * @providesModule Bar
*/ */
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/**
* @providesModule Foo
* @flow
*/
/**
* @providesModule Bar
*/
" "
`; `;
@ -99,11 +67,9 @@ exports[`test use_strict_with_flow.js 1`] = `
(\"\": void); // error (\"\": void); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
// error
\"use strict\"; \"use strict\";
(\"\": void); /* @flow */
" (\"\": void); // error"
`; `;
exports[`test with_flow.js 1`] = ` exports[`test with_flow.js 1`] = `
@ -112,9 +78,8 @@ exports[`test with_flow.js 1`] = `
(\"\": void); // error (\"\": void); // error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error
(\"\": void); (\"\": void); // error"
"
`; `;
exports[`test without_flow.js 1`] = ` exports[`test without_flow.js 1`] = `
@ -123,7 +88,6 @@ exports[`test without_flow.js 1`] = `
(\"\": void); // no error (\"\": void); // no error
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* some other comment */ /* some other comment */
// no error
(\"\": void); (\"\": void); // no error"
"
`; `;

View File

@ -14,18 +14,17 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// fillRect
// moveTo
// error: should be numbers
let tests = [ let tests = [
// fillRect
function(ctx: CanvasRenderingContext2D) { function(ctx: CanvasRenderingContext2D) {
ctx.fillRect(0, 0, 200, 100); ctx.fillRect(0, 0, 200, 100);
}, },
// moveTo
function(ctx: CanvasRenderingContext2D) { function(ctx: CanvasRenderingContext2D) {
ctx.moveTo(\"0\", \"1\"); ctx.moveTo(\"0\", \"1\"); // error: should be numbers
} }
]; ];"
"
`; `;
exports[`test CustomEvent.js 1`] = ` exports[`test CustomEvent.js 1`] = `
@ -40,14 +39,14 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// CustomEvent
let tests = [ let tests = [
// CustomEvent
function(document: Document) { function(document: Document) {
const event = document.createEvent(\"CustomEvent\"); const event = document.createEvent(\"CustomEvent\");
event.initCustomEvent(\"butts\", true, false, { nice: 42 }); event.initCustomEvent(\"butts\", true, false, { nice: 42 });
} }
]; ];"
"
`; `;
exports[`test Document.js 1`] = ` exports[`test Document.js 1`] = `
@ -64,16 +63,16 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// createElement
let tests = [ let tests = [
// createElement
function(document: Document) { function(document: Document) {
(document.createElement(\"canvas\"): HTMLCanvasElement); (document.createElement(\"canvas\"): HTMLCanvasElement);
(document.createElement(\"link\"): HTMLLinkElement); (document.createElement(\"link\"): HTMLLinkElement);
(document.createElement(\"option\"): HTMLOptionElement); (document.createElement(\"option\"): HTMLOptionElement);
(document.createElement(\"select\"): HTMLSelectElement); (document.createElement(\"select\"): HTMLSelectElement);
} }
]; ];"
"
`; `;
exports[`test Element.js 1`] = ` exports[`test Element.js 1`] = `
@ -97,9 +96,9 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// scrollIntoView
// fails
let tests = [ let tests = [
// scrollIntoView
function(element: Element) { function(element: Element) {
element.scrollIntoView(); element.scrollIntoView();
element.scrollIntoView(false); element.scrollIntoView(false);
@ -107,12 +106,13 @@ let tests = [
element.scrollIntoView({ behavior: \"smooth\", block: \"end\" }); element.scrollIntoView({ behavior: \"smooth\", block: \"end\" });
element.scrollIntoView({ block: \"end\" }); element.scrollIntoView({ block: \"end\" });
element.scrollIntoView({ behavior: \"smooth\" }); element.scrollIntoView({ behavior: \"smooth\" });
// fails
element.scrollIntoView({ behavior: \"invalid\" }); element.scrollIntoView({ behavior: \"invalid\" });
element.scrollIntoView({ block: \"invalid\" }); element.scrollIntoView({ block: \"invalid\" });
element.scrollIntoView(1); element.scrollIntoView(1);
} }
]; ];"
"
`; `;
exports[`test HTMLCanvasElement.js 1`] = ` exports[`test HTMLCanvasElement.js 1`] = `
@ -126,13 +126,13 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// getContext
let tests = [ let tests = [
// getContext
function(el: HTMLCanvasElement) { function(el: HTMLCanvasElement) {
(el.getContext(\"2d\"): ?CanvasRenderingContext2D); (el.getContext(\"2d\"): ?CanvasRenderingContext2D);
} }
]; ];"
"
`; `;
exports[`test HTMLElement.js 1`] = ` exports[`test HTMLElement.js 1`] = `
@ -156,9 +156,9 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// scrollIntoView
// fails
let tests = [ let tests = [
// scrollIntoView
function(element: HTMLElement) { function(element: HTMLElement) {
element.scrollIntoView(); element.scrollIntoView();
element.scrollIntoView(false); element.scrollIntoView(false);
@ -166,12 +166,13 @@ let tests = [
element.scrollIntoView({ behavior: \"smooth\", block: \"end\" }); element.scrollIntoView({ behavior: \"smooth\", block: \"end\" });
element.scrollIntoView({ block: \"end\" }); element.scrollIntoView({ block: \"end\" });
element.scrollIntoView({ behavior: \"smooth\" }); element.scrollIntoView({ behavior: \"smooth\" });
// fails
element.scrollIntoView({ behavior: \"invalid\" }); element.scrollIntoView({ behavior: \"invalid\" });
element.scrollIntoView({ block: \"invalid\" }); element.scrollIntoView({ block: \"invalid\" });
element.scrollIntoView(1); element.scrollIntoView(1);
} }
]; ];"
"
`; `;
exports[`test HTMLInputElement.js 1`] = ` exports[`test HTMLInputElement.js 1`] = `
@ -189,19 +190,18 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// setRangeText
// end is required
// invalid value
let tests = [ let tests = [
// setRangeText
function(el: HTMLInputElement) { function(el: HTMLInputElement) {
el.setRangeText(\"foo\"); el.setRangeText(\"foo\");
el.setRangeText(\"foo\", 123); el.setRangeText(\"foo\", 123);
// end is required
el.setRangeText(\"foo\", 123, 234); el.setRangeText(\"foo\", 123, 234);
el.setRangeText(\"foo\", 123, 234, \"select\"); el.setRangeText(\"foo\", 123, 234, \"select\");
el.setRangeText(\"foo\", 123, 234, \"bogus\"); el.setRangeText(\"foo\", 123, 234, \"bogus\"); // invalid value
} }
]; ];"
"
`; `;
exports[`test URL.js 1`] = ` exports[`test URL.js 1`] = `
@ -227,41 +227,40 @@ const q: string = c.search; // correct
const r: string = c.username; // correct const r: string = c.username; // correct
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// correct
// correct
// correct
// correct
// not correct
// correct
// correct
// correct
// correct
// correct
// correct
// correct
// correct
// correct
// correct
// correct
// correct
const a = new URL(\"http://flowtype.org/\"); const a = new URL(\"http://flowtype.org/\");
// correct
const b = new URL(\"/docs\", a); const b = new URL(\"/docs\", a);
// correct
const c = new URL(\"/docs\", \"http://flowtype.org/\"); const c = new URL(\"/docs\", \"http://flowtype.org/\");
// correct
const d: URLSearchParams = c.searchParams; const d: URLSearchParams = c.searchParams;
// correct
const e: string = c.path; const e: string = c.path;
// not correct
const f: string = c.pathname; const f: string = c.pathname;
// correct
const g: string = c.hash; const g: string = c.hash;
// correct
const h: string = c.host; const h: string = c.host;
// correct
const i: string = c.hostname; const i: string = c.hostname;
// correct
const j: string = c.href; const j: string = c.href;
// correct
const l: string = c.origin; const l: string = c.origin;
// correct
const m: string = c.password; const m: string = c.password;
// correct
const n: string = c.pathname; const n: string = c.pathname;
// correct
const o: string = c.port; const o: string = c.port;
// correct
const p: string = c.protocol; const p: string = c.protocol;
// correct
const q: string = c.search; const q: string = c.search;
const r: string = c.username; // correct
" const r: string = c.username; // correct"
`; `;
exports[`test eventtarget.js 1`] = ` exports[`test eventtarget.js 1`] = `
@ -292,31 +291,30 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// attachEvent
// invalid, may be undefined
// valid
// detachEvent
// invalid, may be undefined
// valid
let listener: EventListener = function(event: Event): void {}; let listener: EventListener = function(event: Event): void {};
let tests = [ let tests = [
// attachEvent
function() { function() {
let target = new EventTarget(); let target = new EventTarget();
(target.attachEvent(\"foo\", listener): void); (target.attachEvent(\"foo\", listener): void);
(target.attachEvent && target.attachEvent(\"foo\", listener): void); // invalid, may be undefined
(target.attachEvent && target.attachEvent(\"foo\", listener): void); // valid
}, },
// detachEvent
function() { function() {
let target = new EventTarget(); let target = new EventTarget();
(target.detachEvent(\"foo\", listener): void); (target.detachEvent(\"foo\", listener): void);
(target.detachEvent && target.detachEvent(\"foo\", listener): void); // invalid, may be undefined
(target.detachEvent && target.detachEvent(\"foo\", listener): void); // valid
}, },
function() { function() {
window.onmessage = (event: MessageEvent) => { window.onmessage = (event: MessageEvent) => {
(event.target: window); (event.target: window);
}; };
} }
]; ];"
"
`; `;
exports[`test path2d.js 1`] = ` exports[`test path2d.js 1`] = `
@ -333,19 +331,18 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// arcTo
// valid
// valid
// invalid
let tests = [ let tests = [
// arcTo
function() { function() {
let path = new Path2D(); let path = new Path2D();
(path.arcTo(0, 0, 0, 0, 10): void); (path.arcTo(0, 0, 0, 0, 10): void);
// valid
(path.arcTo(0, 0, 0, 0, 10, 20, 5): void); (path.arcTo(0, 0, 0, 0, 10, 20, 5): void);
(path.arcTo(0, 0, 0, 0, 10, \"20\", 5): void); // valid
(path.arcTo(0, 0, 0, 0, 10, \"20\", 5): void); // invalid
} }
]; ];"
"
`; `;
exports[`test registerElement.js 1`] = ` exports[`test registerElement.js 1`] = `
@ -409,12 +406,9 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// should work with Object.create()
// or with Object.assign()
// should complain about invalid callback parameters
// Error: This might be null
// Error: This might be null
let tests = [ let tests = [
// should work with Object.create()
function() { function() {
document.registerElement(\"custom-element\", { document.registerElement(\"custom-element\", {
prototype: Object.create(HTMLElement.prototype, { prototype: Object.create(HTMLElement.prototype, {
@ -432,6 +426,7 @@ let tests = [
}) })
}); });
}, },
// or with Object.assign()
function() { function() {
document.registerElement(\"custom-element\", { document.registerElement(\"custom-element\", {
prototype: Object.assign(Object.create(HTMLElement.prototype), { prototype: Object.assign(Object.create(HTMLElement.prototype), {
@ -447,20 +442,22 @@ let tests = [
}) })
}); });
}, },
// should complain about invalid callback parameters
function() { function() {
document.registerElement(\"custom-element\", { document.registerElement(\"custom-element\", {
prototype: { prototype: {
attributeChangedCallback( attributeChangedCallback(
localName: string, localName: string,
oldVal: string, oldVal: string,
// Error: This might be null
newVal: string, newVal: string,
// Error: This might be null
namespace: string namespace: string
) {} ) {}
} }
}); });
} }
]; ];"
"
`; `;
exports[`test traversal.js 1`] = ` exports[`test traversal.js 1`] = `
@ -661,24 +658,9 @@ let tests = [
]; ];
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// basic functionality
// rootNode must be a Node
// valid
// invalid
// invalid
// Type Parameters
// NodeFilterInterface
// valid
// invalid
// valid
// invalid
// invalid
// valid
// invalid
// valid
// invalid
// invalid
let tests = [ let tests = [
// basic functionality
function() { function() {
const i: NodeIterator<*, *> = document.createNodeIterator(document.body); const i: NodeIterator<*, *> = document.createNodeIterator(document.body);
const filter: NodeFilter = i.filter; const filter: NodeFilter = i.filter;
@ -693,14 +675,17 @@ let tests = [
typeof NodeFilter.FILTER_REJECT | typeof NodeFilter.FILTER_REJECT |
typeof NodeFilter.FILTER_SKIP = filter.acceptNode(document.body); typeof NodeFilter.FILTER_SKIP = filter.acceptNode(document.body);
}, },
// rootNode must be a Node
function() { function() {
document.createNodeIterator(document.body); document.createNodeIterator(document.body);
document.createNodeIterator({}); // valid
document.createNodeIterator({}); // invalid
}, },
function() { function() {
document.createTreeWalker(document.body); document.createTreeWalker(document.body);
document.createTreeWalker({}); document.createTreeWalker({}); // invalid
}, },
// Type Parameters
function() { function() {
const _root = document.body; const _root = document.body;
const i = document.createNodeIterator(_root, NodeFilter.SHOW_ELEMENT); const i = document.createNodeIterator(_root, NodeFilter.SHOW_ELEMENT);
@ -854,20 +839,25 @@ let tests = [
const previousNode: Node | null = w.previousNode(); const previousNode: Node | null = w.previousNode();
const nextNode: Node | null = w.nextNode(); const nextNode: Node | null = w.nextNode();
}, },
// NodeFilterInterface
function() { function() {
document.createNodeIterator( document.createNodeIterator(
document.body, document.body,
-1, -1,
node => NodeFilter.FILTER_ACCEPT node => NodeFilter.FILTER_ACCEPT
); );
// valid
document.createNodeIterator(document.body, -1, node => \"accept\"); document.createNodeIterator(document.body, -1, node => \"accept\");
// invalid
document.createNodeIterator(document.body, -1, { document.createNodeIterator(document.body, -1, {
accept: node => NodeFilter.FILTER_ACCEPT accept: node => NodeFilter.FILTER_ACCEPT
}); });
// valid
document.createNodeIterator(document.body, -1, { document.createNodeIterator(document.body, -1, {
accept: node => \"accept\" accept: node => \"accept\"
}); });
document.createNodeIterator(document.body, -1, {}); // invalid
document.createNodeIterator(document.body, -1, {}); // invalid
}, },
function() { function() {
document.createTreeWalker( document.createTreeWalker(
@ -875,13 +865,16 @@ let tests = [
-1, -1,
node => NodeFilter.FILTER_ACCEPT node => NodeFilter.FILTER_ACCEPT
); );
// valid
document.createTreeWalker(document.body, -1, node => \"accept\"); document.createTreeWalker(document.body, -1, node => \"accept\");
// invalid
document.createTreeWalker(document.body, -1, { document.createTreeWalker(document.body, -1, {
accept: node => NodeFilter.FILTER_ACCEPT accept: node => NodeFilter.FILTER_ACCEPT
}); });
// valid
document.createTreeWalker(document.body, -1, { accept: node => \"accept\" }); document.createTreeWalker(document.body, -1, { accept: node => \"accept\" });
document.createTreeWalker(document.body, -1, {}); // invalid
document.createTreeWalker(document.body, -1, {}); // invalid
} }
]; ];"
"
`; `;

View File

@ -9,8 +9,7 @@ module.exports = num;
var num = 42; var num = 42;
function bar() {} function bar() {}
bar(); bar();
module.exports = num; module.exports = num;"
"
`; `;
exports[`test test.js 1`] = ` exports[`test test.js 1`] = `
@ -37,15 +36,18 @@ declare var obj: {a?: {b: ?{c: null | {d: number}}}};
const idxResult = idx(obj, obj => obj.a.b.c.d); const idxResult = idx(obj, obj => obj.a.b.c.d);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow // @flow
// test deduping of inferred types
var num = require(\"./import\"); var num = require(\"./import\");
function foo(x) {} function foo(x) {}
foo(0); foo(0);
var a: string = num; var a: string = num;
function unannotated(x) { function unannotated(x) {
return x; return x;
} }
// test deduping of inferred types
const nullToUndefined = val => val === null ? undefined : val; const nullToUndefined = val => val === null ? undefined : val;
function f0(x: ?Object) { function f0(x: ?Object) {
return nullToUndefined(x); return nullToUndefined(x);
} }
@ -58,8 +60,8 @@ function f2(x: ?string) {
function f3(x: ?string) { function f3(x: ?string) {
return nullToUndefined(x); return nullToUndefined(x);
} }
declare var idx: $Facebookism$Idx; declare var idx: $Facebookism$Idx;
declare var obj: { a?: { b: ?{ c: null | { d: number } } } }; declare var obj: { a?: { b: ?{ c: null | { d: number } } } };
const idxResult = idx(obj, obj => obj.a.b.c.d); const idxResult = idx(obj, obj => obj.a.b.c.d);"
"
`; `;

View File

@ -39,26 +39,34 @@ class C1 {
m() {} m() {}
m() {} m() {}
} }
new C1().m(); new C1().m();
class C2 { class C2 {
get m() { get m() {
return 42; return 42;
} }
m() {} m() {}
} }
new C2().m(); new C2().m();
class C3 { class C3 {
set m(x) {} set m(x) {}
m() {} m() {}
} }
new C3().m(); new C3().m();
class C4 { class C4 {
get m() { get m() {
return 42; return 42;
} }
set m(x: number) {} set m(x: number) {}
} }
new C4().m = new C4().m - 42; new C4().m = new C4().m - 42;
class C5 { class C5 {
m() {} m() {}
get m() { get m() {
@ -66,6 +74,6 @@ class C5 {
} }
set m(x: number) {} set m(x: number) {}
} }
new C5().m = new C5().m - 42;
" new C5().m = new C5().m - 42;"
`; `;

View File

@ -16,22 +16,21 @@ function tag2(strings,...values) {
var s3 = tag2 \`la la la\`; var s3 = tag2 \`la la la\`;
(s3.foo: number); // error: string ~> number (s3.foo: number); // error: string ~> number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// error: no prop x in A
// error: string ~> number
// ok: tagged templates can return whatever
// error: string ~> number
class A {} class A {}
var a = new A(); var a = new A();
var s1 = \`l\${a.x}r\`; var s1 = \`l\${a.x}r\`;
// error: no prop x in A
function tag(strings, ...values) { function tag(strings, ...values) {
var x: number = strings[0]; var x: number = strings[0];
// error: string ~> number
return x; return x;
} }
var s2 = tag\`l\${42}r\`; var s2 = tag\`l\${42}r\`;
function tag2(strings, ...values) { function tag2(strings, ...values) {
return { foo: \"\" }; return { foo: \"\" }; // ok: tagged templates can return whatever
} }
var s3 = tag2\`la la la\`; var s3 = tag2\`la la la\`;
(s3.foo: number); (s3.foo: number); // error: string ~> number"
"
`; `;

View File

@ -27,26 +27,30 @@ function keys2union(s: Keys): Union { return s; } // ok
function union2keys(s: Union): Keys { return s; } // ok function union2keys(s: Union): Keys { return s; } // ok
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/** @flow */ /** @flow */
// ok
// ok
function isActive( function isActive(
ad: { state: $Keys<{ PAUSED: string, ACTIVE: string, DELETED: string }> } ad: { state: $Keys<{ PAUSED: string, ACTIVE: string, DELETED: string }> }
): boolean { ): boolean {
return ad.state === \"ACTIVE\"; return ad.state === \"ACTIVE\";
} }
isActive({ state: \"PAUSE\" }); isActive({ state: \"PAUSE\" });
var MyStates = { PAUSED: \"PAUSED\", ACTIVE: \"ACTIVE\", DELETED: \"DELETED\" }; var MyStates = { PAUSED: \"PAUSED\", ACTIVE: \"ACTIVE\", DELETED: \"DELETED\" };
function isActive2(ad: { state: $Keys<typeof MyStates> }): boolean { function isActive2(ad: { state: $Keys<typeof MyStates> }): boolean {
return ad.state === MyStates.ACTIVE; return ad.state === MyStates.ACTIVE;
} }
isActive2({ state: \"PAUSE\" }); isActive2({ state: \"PAUSE\" });
type Keys = $Keys<{ x: any, y: any }>; type Keys = $Keys<{ x: any, y: any }>;
type Union = \"x\" | \"y\"; type Union = \"x\" | \"y\";
function keys2union(s: Keys): Union { function keys2union(s: Keys): Union {
return s; return s;
} }
// ok
function union2keys(s: Union): Keys { function union2keys(s: Union): Keys {
return s; return s;
} } // ok"
"
`; `;

View File

@ -13,16 +13,16 @@ var x = (null : ?number);
(1 == x); (1 == x);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */ /* @flow */
// error
// error
1 == 1; 1 == 1;
\"foo\" == \"bar\"; \"foo\" == \"bar\";
1 == null; 1 == null;
null == 1; null == 1;
1 == \"\"; 1 == \"\";
// error
\"\" == 1; \"\" == 1;
// error
var x = (null: ?number); var x = (null: ?number);
x == 1; x == 1;
1 == x; 1 == x;"
"
`; `;

View File

@ -1,6 +1,5 @@
exports[`test errors.js 1`] = ` exports[`test errors.js 1`] = `
"if (typeof define === \'function\' && define.amd) { } "if (typeof define === \'function\' && define.amd) { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (typeof define === \"function\" && define.amd) {} if (typeof define === \"function\" && define.amd) {}"
"
`; `;

Some files were not shown because too many files have changed in this diff Show More