Bump babylon to 7.0.0-beta.8 (#1118)

* Bump babylon version

* Enable flow predicate tests in babylon
master
Brian Ng 2017-04-04 16:21:56 -05:00 committed by Christopher Chedeau
parent 96b0a33cff
commit d9a4efcc35
10 changed files with 1349 additions and 5 deletions

View File

@ -12,7 +12,7 @@
"dependencies": {
"ast-types": "0.9.8",
"babel-code-frame": "6.22.0",
"babylon": "7.0.0-beta.4",
"babylon": "7.0.0-beta.8",
"chalk": "1.1.3",
"esutils": "2.0.2",
"flow-parser": "0.40.0",

View File

@ -34,12 +34,87 @@ function is_string(x): %checks {
"
`;
exports[`filter.js 2`] = `
"// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(v: Array<T>, cb: P): Array<$Refine<T,P,1>>;
declare var arr: Array<mixed>;
const barr = my_filter(arr, is_string);
(barr: Array<string>);
function is_string(x): %checks {
return typeof x === \\"string\\";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(
v: Array<T>,
cb: P
): Array<$Refine<T, P, 1>>;
declare var arr: Array<mixed>;
const barr = my_filter(arr, is_string);
(barr: Array<string>);
function is_string(x): %checks {
return typeof x === \\"string\\";
}
"
`;
exports[`filter-union.js 1`] = `
"// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(v: Array<T>, cb: P): Array<$Refine<T,P,1>>;
type A = { kind: 'A', u: number }
type B = { kind: 'B', v: string }
type C = { kind: 'C', y: boolean }
type D = { kind: 'D', x: boolean }
type E = { kind: 'E', y: boolean }
declare var ab: Array<A|B|C>;
(my_filter(ab, (x): %checks => x.kind === 'A'): Array<A>); // OK
(my_filter(ab, (x): %checks => x.kind !== 'A'): Array<B|C>); // OK
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(
v: Array<T>,
cb: P
): Array<$Refine<T, P, 1>>;
type A = { kind: \\"A\\", u: number };
type B = { kind: \\"B\\", v: string };
type C = { kind: \\"C\\", y: boolean };
type D = { kind: \\"D\\", x: boolean };
type E = { kind: \\"E\\", y: boolean };
declare var ab: Array<A | B | C>;
(my_filter(ab, (x): %checks => x.kind === \\"A\\"): Array<A>); // OK
(my_filter(ab, (x): %checks => x.kind !== \\"A\\"): Array<B | C>); // OK
"
`;
exports[`filter-union.js 2`] = `
"// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(v: Array<T>, cb: P): Array<$Refine<T,P,1>>;
type A = { kind: 'A', u: number }
@ -110,6 +185,106 @@ var e = refine2(c, d, is_string_and_number);
(e: string);
declare function refine2<T, P: $Pred<2>>(v: T, w: T, cb: P): $Refine<T,P,1>;
// function refine_fst(v, w, cb)
// { if (cb(v, w)) { return w; } else { throw new Error(); } }
function is_string(x): boolean %checks {
return typeof x === \\"string\\";
}
function is_string_and_number(x, y): %checks {
return typeof x === \\"string\\" && typeof y === \\"number\\";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
/*
$Pred<N> is an \\"abstract predicate type\\", i.e. denotes a (function) type that
refines N variables. So if \`cb\` is a function, then it should be refining
exactly N argument. It is abstract in that we do not need to specify:
(a) which variables are going to be refined (just the number), or (b) what
exactly the refinement (predicate) is going to be.
$Refine<T,P,k> is a refinement type, that refines type T with the k-th
argument that gets refined by an abstract preficate type P.
*/
declare function refine<T, P: $Pred<1>>(v: T, cb: P): $Refine<T, P, 1>;
// function refine(v, cb)
// { if (cb(v)) { return v; } else { throw new Error(); } }
/*
Use case
*/
declare var a: mixed;
var b = refine(a, is_string);
(b: string);
declare function refine_fst<T, P: $Pred<2>>(
v: T,
w: T,
cb: P
): $Refine<T, P, 1>;
// function refine_fst(v, w, cb)
// { if (cb(v, w)) { return v; } else { throw new Error(); } }
declare var c: mixed;
declare var d: mixed;
var e = refine2(c, d, is_string_and_number);
(e: string);
declare function refine2<T, P: $Pred<2>>(v: T, w: T, cb: P): $Refine<T, P, 1>;
// function refine_fst(v, w, cb)
// { if (cb(v, w)) { return w; } else { throw new Error(); } }
function is_string(x): boolean %checks {
return typeof x === \\"string\\";
}
function is_string_and_number(x, y): %checks {
return typeof x === \\"string\\" && typeof y === \\"number\\";
}
"
`;
exports[`refine.js 2`] = `
"// @flow
/*
$Pred<N> is an \\"abstract predicate type\\", i.e. denotes a (function) type that
refines N variables. So if \`cb\` is a function, then it should be refining
exactly N argument. It is abstract in that we do not need to specify:
(a) which variables are going to be refined (just the number), or (b) what
exactly the refinement (predicate) is going to be.
$Refine<T,P,k> is a refinement type, that refines type T with the k-th
argument that gets refined by an abstract preficate type P.
*/
declare function refine<T, P: $Pred<1>>(v: T, cb: P): $Refine<T,P,1>;
// function refine(v, cb)
// { if (cb(v)) { return v; } else { throw new Error(); } }
/*
Use case
*/
declare var a: mixed;
var b = refine(a, is_string);
(b: string);
declare function refine_fst<T, P: $Pred<2>>(v: T, w: T, cb: P): $Refine<T,P,1>;
// function refine_fst(v, w, cb)
// { if (cb(v, w)) { return v; } else { throw new Error(); } }
declare var c: mixed;
declare var d: mixed;
var e = refine2(c, d, is_string_and_number);
(e: string);
declare function refine2<T, P: $Pred<2>>(v: T, w: T, cb: P): $Refine<T,P,1>;
// function refine_fst(v, w, cb)
@ -186,6 +361,57 @@ const b = my_filter(a, is_string);
(b: Array<number>);
// Sanity check B: Passing non-predicate function to filter
declare var c: Array<mixed>;
const d = my_filter(c, is_string_regular);
(d: Array<string>);
function is_string(x): boolean %checks {
return typeof x === \\"string\\";
}
function is_string_regular(x): boolean {
return typeof x === \\"string\\";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare function my_filter<T, P: $Pred<1>>(
v: Array<T>,
cb: P
): Array<$Refine<T, P, 1>>;
// Sanity check A: filtering the wrong type
declare var a: Array<mixed>;
const b = my_filter(a, is_string);
(b: Array<number>);
// Sanity check B: Passing non-predicate function to filter
declare var c: Array<mixed>;
const d = my_filter(c, is_string_regular);
(d: Array<string>);
function is_string(x): boolean %checks {
return typeof x === \\"string\\";
}
function is_string_regular(x): boolean {
return typeof x === \\"string\\";
}
"
`;
exports[`sanity-filter.js 2`] = `
"// @flow
declare function my_filter<T, P: $Pred<1>>(v: Array<T>, cb: P): Array<$Refine<T,P,1>>;
// Sanity check A: filtering the wrong type
declare var a: Array<mixed>;
const b = my_filter(a, is_string);
(b: Array<number>);
// Sanity check B: Passing non-predicate function to filter
declare var c: Array<mixed>;
const d = my_filter(c, is_string_regular);
@ -232,6 +458,47 @@ exports[`sanity-filter-union.js 1`] = `
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(v: Array<T>, cb: P): Array<$Refine<T,P,1>>;
type A = { kind: 'A', u: number }
type B = { kind: 'B', v: string }
type C = { kind: 'C', y: boolean }
type D = { kind: 'D', x: boolean }
type E = { kind: 'E', y: boolean }
declare var ab: Array<A|B|C>;
(my_filter(ab, (x): %checks => x.kind === 'A'): Array<B>); // ERROR
(my_filter(ab, (x): %checks => x.kind !== 'A'): Array<A|C>); // ERROR
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(
v: Array<T>,
cb: P
): Array<$Refine<T, P, 1>>;
type A = { kind: \\"A\\", u: number };
type B = { kind: \\"B\\", v: string };
type C = { kind: \\"C\\", y: boolean };
type D = { kind: \\"D\\", x: boolean };
type E = { kind: \\"E\\", y: boolean };
declare var ab: Array<A | B | C>;
(my_filter(ab, (x): %checks => x.kind === \\"A\\"): Array<B>); // ERROR
(my_filter(ab, (x): %checks => x.kind !== \\"A\\"): Array<A | C>); // ERROR
"
`;
exports[`sanity-filter-union.js 2`] = `
"// @flow
// Filter the contents of an array
declare function my_filter<T, P: $Pred<1>>(v: Array<T>, cb: P): Array<$Refine<T,P,1>>;
type A = { kind: 'A', u: number }
@ -294,6 +561,102 @@ function is_string_and_number(x, y): %checks {
}
// Sanity check C: expecting a predicate function but passed a non-predicate one
var e = refine(a, is_string_regular); // ERROR: is_string_regular is not a
// predicate function
(e: number);
////////////////////////////////////////////////////////////////////////////////
function is_string(x): %checks {
return typeof x === \\"string\\";
}
function is_string_regular(x) {
return typeof x === \\"string\\";
}
function is_string_and_number(x, y): %checks {
return typeof x === \\"string\\" && typeof y === \\"number\\";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check A: the refinment position index is outside of the allowed range
declare function refine<T, P: $Pred<1>>(v: T, cb: P): $Refine<T, P, 2>;
declare var a: mixed;
var b = refine(a, is_string); // ERROR: index out of bounds
(b: string);
// Sanity check B: refine2 expects a function that accepts 3 arguments but
// it is called with a function that takes 2
declare var c: mixed;
declare var d: mixed;
declare var e: mixed;
declare function refine3<T, P: $Pred<3>>(
u: T,
v: T,
w: T,
cb: P
): $Refine<T, P, 1>;
var e = refine3(c, d, e, is_string_and_number);
(e: string);
function is_string_and_number(x, y): %checks {
return typeof x === \\"string\\" && typeof y === \\"number\\";
}
// Sanity check C: expecting a predicate function but passed a non-predicate one
var e = refine(a, is_string_regular); // ERROR: is_string_regular is not a
// predicate function
(e: number);
////////////////////////////////////////////////////////////////////////////////
function is_string(x): %checks {
return typeof x === \\"string\\";
}
function is_string_regular(x) {
return typeof x === \\"string\\";
}
function is_string_and_number(x, y): %checks {
return typeof x === \\"string\\" && typeof y === \\"number\\";
}
"
`;
exports[`sanity-refine.js 2`] = `
"// @flow
// Sanity check A: the refinment position index is outside of the allowed range
declare function refine<T, P: $Pred<1>>(v: T, cb: P): $Refine<T,P,2>;
declare var a: mixed;
var b = refine(a, is_string); // ERROR: index out of bounds
(b: string);
// Sanity check B: refine2 expects a function that accepts 3 arguments but
// it is called with a function that takes 2
declare var c: mixed;
declare var d: mixed;
declare var e: mixed;
declare function refine3<T, P: $Pred<3>>(u: T, v: T, w: T, cb: P): $Refine<T,P,1>;
var e = refine3(c, d, e, is_string_and_number);
(e: string);
function is_string_and_number(x, y): %checks {
return typeof x === \\"string\\" && typeof y === \\"number\\";
}
// Sanity check C: expecting a predicate function but passed a non-predicate one
var e = refine(a, is_string_regular); // ERROR: is_string_regular is not a
// predicate function

View File

@ -1 +1,2 @@
run_spec(__dirname);
run_spec(__dirname, { parser: "babylon" });

View File

@ -30,6 +30,92 @@ if (m.bind(o)) {
}
class D {
m: Function;
n() {
if(this.m({})) { }
}
}
declare var m: Function;
const x = \\"\\";
if (m.bind(this)(x)) { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity checks:
// - use of bind in a position of a function predicate.
// (This case should fall through, as method calls
// are currently not supported.) The original behavior
// (including \`havoc\`) should be retained.
class C {
m() {
return true;
}
a: 1;
n() {
if (this.m.bind(this)) {
this.a;
}
}
}
declare var m: Function;
const o = { a: 1 };
if (m.bind(o)) {
o.a;
}
class D {
m: Function;
n() {
if (this.m({})) {
}
}
}
declare var m: Function;
const x = \\"\\";
if (m.bind(this)(x)) {
}
"
`;
exports[`function-bind.js 2`] = `
"// @flow
// Sanity checks:
// - use of bind in a position of a function predicate.
// (This case should fall through, as method calls
// are currently not supported.) The original behavior
// (including \`havoc\`) should be retained.
class C {
m() {
return true;
}
a: 1;
n() {
if(this.m.bind(this)) {
this.a;
}
}
}
declare var m: Function;
const o = { a: 1 };
if (m.bind(o)) {
o.a;
}
class D {
m: Function;
@ -126,6 +212,46 @@ function foo(x: number | string | Array<string>): number {
"
`;
exports[`function-union.js 2`] = `
"// @flow
declare function f1(x: mixed): boolean %checks(typeof x === \\"string\\");
declare function f2(x: mixed): boolean %checks(Array.isArray(x));
declare var cond: boolean;
// Feature check:
function foo(x: number | string | Array<string>): number {
var f = (cond) ? f1 : f2;
if (f(x)) {
return x.length;
} else {
return 1;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare function f1(x: mixed): boolean %checks(typeof x === \\"string\\");
declare function f2(x: mixed): boolean %checks(Array.isArray(x));
declare var cond: boolean;
// Feature check:
function foo(x: number | string | Array<string>): number {
var f = cond ? f1 : f2;
if (f(x)) {
return x.length;
} else {
return 1;
}
}
"
`;
exports[`is-string-decl.js 1`] = `
"// @flow
@ -167,6 +293,47 @@ function foo(x: string | Array<string>): string {
"
`;
exports[`is-string-decl.js 2`] = `
"// @flow
declare function is_string(x: mixed): boolean %checks(typeof x === \\"string\\");
declare function is_number(x: mixed): boolean %checks(typeof x === \\"number\\");
// Feature check:
function foo(x: string | Array<string>): string {
if (is_string(x)) {
// The use of \`is_string\` as a conditional check
// should guarantee the narrowing of the type of \`x\`
// to string.
return x;
} else {
// Accordingly the negation of the above check
// guarantees that \`x\` here is an Array<string>
return x.join();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare function is_string(x: mixed): boolean %checks(typeof x === \\"string\\");
declare function is_number(x: mixed): boolean %checks(typeof x === \\"number\\");
// Feature check:
function foo(x: string | Array<string>): string {
if (is_string(x)) {
// The use of \`is_string\` as a conditional check
// should guarantee the narrowing of the type of \`x\`
// to string.
return x;
} else {
// Accordingly the negation of the above check
// guarantees that \`x\` here is an Array<string>
return x.join();
}
}
"
`;
exports[`logical-or.js 1`] = `
"// @flow
@ -218,6 +385,57 @@ Number(dollars) || 0;
"
`;
exports[`logical-or.js 2`] = `
"// @flow
// Sanity check:
// - conditional functions do not affect behavior of conditional
// expressions (e.g. \`||\`)
declare function r(x: string): number;
var s = 'a';
var n = r(s) || 1;
(n: number);
var x = \\"\\";
if (x = r(s) || 1) {
(x: number);
}
declare var dollars: mixed;
function foo(x: mixed) { return 1; }
(foo(dollars) || 0);
(Number(dollars) || 0);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check:
// - conditional functions do not affect behavior of conditional
// expressions (e.g. \`||\`)
declare function r(x: string): number;
var s = \\"a\\";
var n = r(s) || 1;
(n: number);
var x = \\"\\";
if ((x = r(s) || 1)) {
(x: number);
}
declare var dollars: mixed;
function foo(x: mixed) {
return 1;
}
foo(dollars) || 0;
Number(dollars) || 0;
"
`;
exports[`object-invariant.js 1`] = `
"// @flow
@ -270,6 +488,58 @@ function f(_this: { m: ?Meeting }): string {
"
`;
exports[`object-invariant.js 2`] = `
"// @flow
// Sanity check:
// - preserving \`havoc\` semantics
type Meeting = {
organizer: ?Invitee,
es: Array<Invitee>
}
type Invitee = {
fbid: number
}
function f(_this: { m: ?Meeting }): string {
if (!_this.m) {
return \\"0\\";
}
if (_this.m.es.some((a) => a.fbid === 0)) {
}
return \\"3\\";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check:
// - preserving \`havoc\` semantics
type Meeting = {
organizer: ?Invitee,
es: Array<Invitee>
};
type Invitee = {
fbid: number
};
function f(_this: { m: ?Meeting }): string {
if (!_this.m) {
return \\"0\\";
}
if (_this.m.es.some(a => a.fbid === 0)) {
}
return \\"3\\";
}
"
`;
exports[`orig-string-tag-check.js 1`] = `
"// @flow
@ -298,6 +568,34 @@ function foo(x: string | Array<string>): string {
"
`;
exports[`orig-string-tag-check.js 2`] = `
"// @flow
// The original first-order case
function foo(x: string | Array<string>): string {
if (typeof x === \\"string\\") {
return x; // [ERROR] x: Array<string> doesn't match return type
}
else {
return x.join(); // [ERROR] x: string doesn't have .join method
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// The original first-order case
function foo(x: string | Array<string>): string {
if (typeof x === \\"string\\") {
return x; // [ERROR] x: Array<string> doesn't match return type
} else {
return x.join(); // [ERROR] x: string doesn't have .join method
}
}
"
`;
exports[`sanity-fall-through.js 1`] = `
"// @flow
@ -329,6 +627,37 @@ function foo(s: Array<string>): string {
"
`;
exports[`sanity-fall-through.js 2`] = `
"// @flow
// Sanity check:
// - we should still be getting an error at the second return statement
declare function pred<T>(x: T): boolean;
function foo(s: Array<string>): string {
if (pred(s)) {
return \\"1\\";
}
return 1;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check:
// - we should still be getting an error at the second return statement
declare function pred<T>(x: T): boolean;
function foo(s: Array<string>): string {
if (pred(s)) {
return \\"1\\";
}
return 1;
}
"
`;
exports[`sanity-invalid-calls.js 1`] = `
"// @flow
@ -371,6 +700,48 @@ function foo(s: Array<string>): string {
"
`;
exports[`sanity-invalid-calls.js 2`] = `
"// @flow
// Sanity check:
// - invalid calls at predicate positions
declare function pred<T>(x: T): boolean;
function foo(s: Array<string>): string {
if ((1)(s)) {
return \\"1\\";
}
if ((pred + 1)(\\"s\\")) {
return \\"1\\";
}
return \\"1\\"
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check:
// - invalid calls at predicate positions
declare function pred<T>(x: T): boolean;
function foo(s: Array<string>): string {
if (1(s)) {
return \\"1\\";
}
if ((pred + 1)(\\"s\\")) {
return \\"1\\";
}
return \\"1\\";
}
"
`;
exports[`sanity-is-string-bug.js 1`] = `
"// @flow
@ -406,6 +777,41 @@ function bar(x: string | Array<string>): string {
"
`;
exports[`sanity-is-string-bug.js 2`] = `
"// @flow
declare function is_string(x: mixed): boolean %checks(typeof x === \\"string\\");
declare function is_number(x: mixed): boolean %checks(typeof x === \\"number\\");
// Sanity check:
// - Erroneous logic
function bar(x: string | Array<string>): string {
if (is_number(x)) {
return x;
} else {
return x.join(); // error: both string and Array<string> can flow to x
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare function is_string(x: mixed): boolean %checks(typeof x === \\"string\\");
declare function is_number(x: mixed): boolean %checks(typeof x === \\"number\\");
// Sanity check:
// - Erroneous logic
function bar(x: string | Array<string>): string {
if (is_number(x)) {
return x;
} else {
return x.join(); // error: both string and Array<string> can flow to x
}
}
"
`;
exports[`sanity-parameter-mismatch.js 1`] = `
"// @flow
@ -431,6 +837,31 @@ foo(3, 3);
"
`;
exports[`sanity-parameter-mismatch.js 2`] = `
"// @flow
// Sanity check: make sure the parameters are checked as usual
declare function foo(
input: mixed,
types: string | Array<string>
): boolean %checks(typeof input === \\"string\\" || Array.isArray(input));
foo(3, 3);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check: make sure the parameters are checked as usual
declare function foo(
input: mixed,
types: string | Array<string>
): boolean %checks(typeof input === \\"string\\" || Array.isArray(input));
foo(3, 3);
"
`;
exports[`sanity-pred-with-body.js 1`] = `
"// @flow
@ -467,6 +898,42 @@ function foo(x: string | Array<string>): string {
"
`;
exports[`sanity-pred-with-body.js 2`] = `
"// @flow
// Sanity check:
// - predicate functions cannot have bodies (can only be declarations)
function pred(x: mixed): boolean %checks(typeof x === \\"string\\") { // error: cannot use pred type here
return typeof x === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (pred(x)) {
return x;
}
return \\"1\\"
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check:
// - predicate functions cannot have bodies (can only be declarations)
function pred(x: mixed): boolean %checks(typeof x === \\"string\\") {
// error: cannot use pred type here
return typeof x === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (pred(x)) {
return x;
}
return \\"1\\";
}
"
`;
exports[`sanity-return-type.js 1`] = `
"// @flow
@ -477,3 +944,14 @@ declare function f2(x: mixed): string %checks(Array.isArray(x));
declare function f2(x: mixed): string %checks(Array.isArray(x));
"
`;
exports[`sanity-return-type.js 2`] = `
"// @flow
declare function f2(x: mixed): string %checks(Array.isArray(x));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare function f2(x: mixed): string %checks(Array.isArray(x));
"
`;

View File

@ -1 +1,2 @@
run_spec(__dirname);
run_spec(__dirname, { parser: 'babylon' });

View File

@ -59,6 +59,65 @@ function bak(z: string | number): number {
"
`;
exports[`sanity.js 2`] = `
"// @flow
// Sanity check: shouldn't be allowed to declare a predicate AND use \`chekcs\`
function check(y): %checks(typeof y === \\"string\\") {
return typeof y === \\"number\\";
}
declare var y: number | boolean;
if (check(y)) {
(y: number);
}
// Sanity: disallowed body
function indirect_is_number(y): %checks {
var y = 1;
return typeof y === \\"number\\";
}
function bak(z: string | number): number {
if (indirect_is_number(z)) {
return z;
} else {
return z.length;
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Sanity check: shouldn't be allowed to declare a predicate AND use \`chekcs\`
function check(y): %checks(typeof y === \\"string\\") {
return typeof y === \\"number\\";
}
declare var y: number | boolean;
if (check(y)) {
(y: number);
}
// Sanity: disallowed body
function indirect_is_number(y): %checks {
var y = 1;
return typeof y === \\"number\\";
}
function bak(z: string | number): number {
if (indirect_is_number(z)) {
return z;
} else {
return z.length;
}
}
"
`;
exports[`sanity-multi-params.js 1`] = `
"// @flow
@ -92,6 +151,39 @@ function foo(x: string | Array<string>): string {
"
`;
exports[`sanity-multi-params.js 2`] = `
"// @flow
// Feature: multi params
function multi_param(w,x,y,z): %checks {
return typeof z === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (multi_param(\\"1\\", \\"2\\", x, \\"3\\")) {
return x;
} else {
return x.join();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Feature: multi params
function multi_param(w, x, y, z): %checks {
return typeof z === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (multi_param(\\"1\\", \\"2\\", x, \\"3\\")) {
return x;
} else {
return x.join();
}
}
"
`;
exports[`sanity-ordering.js 1`] = `
"// @flow
@ -133,6 +225,47 @@ function dotAccess(head, create) {
"
`;
exports[`sanity-ordering.js 2`] = `
"// @flow
declare var key: string;
declare var obj: { page: ?Object; };
if (dotAccess(obj)) {
(obj.page: Object);
}
function dotAccess(head, create) {
const path = 'path.location';
const stack = path.split('.');
do {
const key = stack.shift();
head = head[key] || create && (head[key] = {});
} while (stack.length && head);
return head;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare var key: string;
declare var obj: { page: ?Object };
if (dotAccess(obj)) {
(obj.page: Object);
}
function dotAccess(head, create) {
const path = \\"path.location\\";
const stack = path.split(\\".\\");
do {
const key = stack.shift();
head = head[key] || (create && (head[key] = {}));
} while (stack.length && head);
return head;
}
"
`;
exports[`sanity-unbound-var.js 1`] = `
"// @flow
@ -172,6 +305,45 @@ function foo(x: string | Array<string>): string {
"
`;
exports[`sanity-unbound-var.js 2`] = `
"// @flow
declare var y: mixed;
// Sanity check: this should fail, because the preficate function
// checks \`y\` instead of \`x\`.
function err(x): %checks {
return typeof y === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (err(x)) {
return x;
} else {
return x.join();
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare var y: mixed;
// Sanity check: this should fail, because the preficate function
// checks \`y\` instead of \`x\`.
function err(x): %checks {
return typeof y === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (err(x)) {
return x;
} else {
return x.join();
}
}
"
`;
exports[`simple-predicate-func.js 1`] = `
"// @flow
@ -323,6 +495,157 @@ declare function from_two_strings(x: string, y: string): void;
"
`;
exports[`simple-predicate-func.js 2`] = `
"// @flow
function is_string(y): %checks {
return typeof y === \\"string\\";
}
function is_bool(y): %checks {
return typeof y === \\"boolean\\";
}
function is_number(y): %checks {
return typeof y === \\"number\\";
}
// Feature check:
function foo(x: string | Array<string>): string {
if (is_string(x)) {
// The use of \`is_string\` as a conditional check
// should guarantee the narrowing of the type of \`x\`
// to string.
return x;
} else {
// Accordingly the negation of the above check
// guarantees that \`x\` here is an Array<string>
return x.join();
}
}
// Same as above but refining an offset
function bar(z: { f: string | Array<string>}): string {
if (is_string(z.f)) {
return z.f;
} else {
return z.f.join();
}
}
function is_number_or_bool(y): %checks {
return is_number(y) || is_bool(y);
}
function baz(z: string | number): number {
if (is_number_or_bool(z)) {
return z;
} else {
return z.length;
}
}
// Feature: multi params
function multi_param(w,x,y,z): %checks {
return typeof z === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (multi_param(\\"1\\", \\"2\\", \\"3\\", x)) {
return x;
} else {
return x.join();
}
}
function foo(a, b) {
if (two_strings(a, b)) {
from_two_strings(a, b);
}
}
function two_strings(x,y): %checks {
return is_string(x) && is_string(y) ;
}
declare function from_two_strings(x: string, y: string): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
function is_string(y): %checks {
return typeof y === \\"string\\";
}
function is_bool(y): %checks {
return typeof y === \\"boolean\\";
}
function is_number(y): %checks {
return typeof y === \\"number\\";
}
// Feature check:
function foo(x: string | Array<string>): string {
if (is_string(x)) {
// The use of \`is_string\` as a conditional check
// should guarantee the narrowing of the type of \`x\`
// to string.
return x;
} else {
// Accordingly the negation of the above check
// guarantees that \`x\` here is an Array<string>
return x.join();
}
}
// Same as above but refining an offset
function bar(z: { f: string | Array<string> }): string {
if (is_string(z.f)) {
return z.f;
} else {
return z.f.join();
}
}
function is_number_or_bool(y): %checks {
return is_number(y) || is_bool(y);
}
function baz(z: string | number): number {
if (is_number_or_bool(z)) {
return z;
} else {
return z.length;
}
}
// Feature: multi params
function multi_param(w, x, y, z): %checks {
return typeof z === \\"string\\";
}
function foo(x: string | Array<string>): string {
if (multi_param(\\"1\\", \\"2\\", \\"3\\", x)) {
return x;
} else {
return x.join();
}
}
function foo(a, b) {
if (two_strings(a, b)) {
from_two_strings(a, b);
}
}
function two_strings(x, y): %checks {
return is_string(x) && is_string(y);
}
declare function from_two_strings(x: string, y: string): void;
"
`;
exports[`simple-predicate-func-post.js 1`] = `
"// @flow
@ -369,3 +692,50 @@ function is_string(x): %checks {
}
"
`;
exports[`simple-predicate-func-post.js 2`] = `
"// @flow
// Feature check:
// The predicate function is defined after the conditional check
function foo(x: string | Array<string>): string {
if (is_string(x)) {
// The use of \`is_string\` as a conditional check
// should guarantee the narrowing of the type of \`x\`
// to string.
return x;
} else {
// Accordingly the negation of the above check
// guarantees that \`x\` here is an Array<string>
return x.join();
}
}
function is_string(x): %checks {
return typeof x === \\"string\\";
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Feature check:
// The predicate function is defined after the conditional check
function foo(x: string | Array<string>): string {
if (is_string(x)) {
// The use of \`is_string\` as a conditional check
// should guarantee the narrowing of the type of \`x\`
// to string.
return x;
} else {
// Accordingly the negation of the above check
// guarantees that \`x\` here is an Array<string>
return x.join();
}
}
function is_string(x): %checks {
return typeof x === \\"string\\";
}
"
`;

View File

@ -1 +1,2 @@
run_spec(__dirname);
run_spec(__dirname, { parser: "babylon" });

View File

@ -15,6 +15,21 @@ declare function f2(x: mixed): boolean %checks;
"
`;
exports[`fail-0.js 2`] = `
"// @flow
// Error: 'declare', 'checks' but missing predicate
declare function f2(x: mixed): boolean %checks;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Error: 'declare', 'checks' but missing predicate
declare function f2(x: mixed): boolean %checks;
"
`;
exports[`fail-1.js 1`] = `
"// @flow
@ -30,6 +45,21 @@ function f6(x: mixed): %checks(x !== null) {}
"
`;
exports[`fail-1.js 2`] = `
"// @flow
// Error: no return statement
function f6(x: mixed): %checks (x !== null) { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Error: no return statement
function f6(x: mixed): %checks(x !== null) {}
"
`;
exports[`fail-2.js 1`] = `
"// @flow
@ -47,6 +77,23 @@ var a2 = (x: mixed): %checks(x !== null) => {
"
`;
exports[`fail-2.js 2`] = `
"// @flow
var a2 = (x: mixed): %checks (x !== null) => { // Error: body form
var x = 1; return x;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
var a2 = (x: mixed): %checks(x !== null) => {
// Error: body form
var x = 1;
return x;
};
"
`;
exports[`fail-3.js 1`] = `
"// @flow
@ -68,6 +115,27 @@ var a2 = (x: mixed): %checks(x !== null) => x !== null;
"
`;
exports[`fail-3.js 2`] = `
"// @flow
// Cannot declare predicate with a function body is present.
function f5(x: mixed): %checks (x !== null) { return x !== null }
var a2 = (x: mixed): %checks (x !== null) => x !== null;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
// Cannot declare predicate with a function body is present.
function f5(x: mixed): %checks(x !== null) {
return x !== null;
}
var a2 = (x: mixed): %checks(x !== null) => x !== null;
"
`;
exports[`pass.js 1`] = `
"// @flow
@ -128,3 +196,64 @@ declare function f(x: mixed): checks;
typeof x === null;
"
`;
exports[`pass.js 2`] = `
"// @flow
declare function f1(x: mixed): boolean;
declare function f3(x: mixed): boolean %checks (x !== null);
declare function f4(x: mixed): boolean %checks (x !== null);
function f7(x: mixed): %checks { return x !== null }
var a0 = (x: mixed) => x !== null;
var a1 = (x: mixed): %checks => x !== null;
(x): %checks => x !== null;
const insert_a_really_big_predicated_arrow_function_name_here = (x)
: %checks => x !== null;
declare var x;
(x)
checks => 123;
type checks = any;
declare function f(x: mixed): checks
(typeof x === null);
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// @flow
declare function f1(x: mixed): boolean;
declare function f3(x: mixed): boolean %checks(x !== null);
declare function f4(x: mixed): boolean %checks(x !== null);
function f7(x: mixed): %checks {
return x !== null;
}
var a0 = (x: mixed) => x !== null;
var a1 = (x: mixed): %checks => x !== null;
(x): %checks => x !== null;
const insert_a_really_big_predicated_arrow_function_name_here = (x): %checks =>
x !== null;
declare var x;
x;
checks => 123;
type checks = any;
declare function f(x: mixed): checks;
typeof x === null;
"
`;

View File

@ -1 +1,2 @@
run_spec(__dirname);
run_spec(__dirname, { parser: "babylon" });

View File

@ -274,14 +274,14 @@ babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.21.0:
lodash "^4.2.0"
to-fast-properties "^1.0.1"
babylon@7.0.0-beta.8:
version "7.0.0-beta.8"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.8.tgz#2bdc5ae366041442c27e068cce6f0d7c06ea9949"
babylon@^6.11.0, babylon@^6.13.0:
version "6.15.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e"
babylon@babylon@7.0.0-beta.4:
version "7.0.0-beta.4"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.4.tgz#82db799d2667f61bbaf34456dbfa91c37613459d"
balanced-match@^0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"