Preserve empty line after comment (#493)

The logic was already working, it was just special-cased to the first comment of the file! Presumably because the new line detection logic used to be broken ;)

I manually checked the first 10 snapshots and they are all legit, so I assume that all of them are.

Fixes #356
master
Christopher Chedeau 2017-01-27 11:05:41 -08:00 committed by James Long
parent 8f26568bc8
commit 956779ec17
51 changed files with 175 additions and 8 deletions

View File

@ -372,7 +372,6 @@ function printComments(path, print, options) {
var parent = path.getParentNode();
var printed = print(path);
var comments = n.Node.check(value) && types.getFieldValue(value, "comments");
var isFirstInProgram = n.Program.check(parent) && parent.body[0] === value;
if (!comments || comments.length === 0) {
return printed;
@ -392,14 +391,8 @@ function printComments(path, print, options) {
) {
leadingParts.push(printLeadingComment(commentPath, print, options));
// 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.
const text = options.originalText;
if (
isFirstInProgram &&
util.hasNewline(text, util.skipNewline(text, util.locEnd(comment)))
) {
if (util.hasNewline(text, util.skipNewline(text, util.locEnd(comment)))) {
leadingParts.push(hardline);
}
} else if (trailing) {

View File

@ -27,6 +27,7 @@ import a from \"a\";
a();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/* @flow */
\"use strict\";
import a from \"a\";

View File

@ -107,6 +107,7 @@ function param_anno2(
// 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 => {
return {
@ -149,6 +150,7 @@ function foo() {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
let myClassInstance: MyClass = null;
// forward ref ok, null ~> class error
function bar(): MyClass {
return null; // forward ref ok, null ~> class error
}

View File

@ -107,6 +107,7 @@ function reduce_test() {
});
/* Added later, because the above is insufficient */
// acc is element type of array when no init is provided
[\"\"].reduce((acc, str) => acc * str.length); // error, string ~> number
[\"\"].reduceRight((acc, str) => acc * str.length); // error, string ~> number

View File

@ -68,6 +68,7 @@ async function f1(): Promise<boolean> {
// await: (p: Promise<T> | T) => T
//
async function f2(p: Promise<number>): Promise<number> {
var x: number = await p;
var y: number = await 1;
@ -86,10 +87,12 @@ async function f4(p: Promise<number>): Promise<boolean> {
// async arrow functions
//
var f5: () => Promise<number> = async () => await 1;
// async methods
//
class C {
async m() {
return 1;
@ -106,6 +109,7 @@ class C {
}
// async function props
var obj = { f: async () => await 1 };
var objf: () => Promise<number> = obj.f;
"
@ -322,9 +326,11 @@ function test1() {
//
// void returns:
//
// inference should produce return type Promise<void>
// in the absence of an explicit return
//
function test2() {
async function voidoid1() {
console.log(\"HEY\");
@ -336,6 +342,7 @@ function test2() {
// annotated return type of Promise<void> should work
//
function test3() {
async function voidoid4(): Promise<void> { // ok
console.log(\"HEY\");
@ -346,6 +353,7 @@ function test3() {
// (note: misannotated return types with explicit
// return statements are covered in async.js)
//
function test4() {
async function voidoid5(): void { // error, void != Promise<void>
console.log(\"HEY\");

View File

@ -44,6 +44,7 @@ x ^= 0;
x &= 0;
// regression tests -- OK to assign consts like this:
const { foo } = { foo: \"foo\" };
const [bar] = [\"bar\"];
(foo: number); // error: string ~> number
@ -298,6 +299,7 @@ function type_reassign() {
}
// class x *
function class_type() {
class A {}
type A = number; // error: name already bound
@ -324,6 +326,7 @@ function class_var() {
}
// let x *
function let_type() {
let A = 0;
type A = number; // error: name already bound
@ -350,6 +353,7 @@ function let_var() {
}
// const x *
function const_type() {
const A = 0;
type A = number; // error: name already bound
@ -381,6 +385,7 @@ function const_reassign() {
}
// var x *
function var_type() {
var A = 0;
type A = number; // error: name already bound
@ -407,6 +412,7 @@ function var_var() {
}
// function x *
function function_toplevel() {
function a() {}
function a() {}
@ -420,6 +426,7 @@ function function_block() {
}
// corner cases
function var_shadow_nested_scope() {
{
let x = 0;
@ -439,6 +446,7 @@ function type_shadow_nested_scope() {
}
// fn params name clash
function fn_params_name_clash(x, x /* error: x already bound */) {}
function fn_params_clash_fn_binding(x, y) {
let x = 0; // error: x already bound
@ -788,6 +796,7 @@ type T1 = T2; // ok
type T2 = number;
// --- lets ---
// to be correct, we would
// - not allow forward refs to lets from value positions,
// while let is in TDZ.
@ -799,6 +808,7 @@ type T2 = number;
// a lambda runs. But a simple conservative approach would prohibit
// forward references to let/consts from within lambdas entirely,
// which would be annoying. TODO
function f0() {
var v = x * c; // errors, let + const referenced before decl
let x = 0;
@ -860,15 +870,18 @@ function f5() {
// value (i.e., class or function). this is a basic flaw in our
// phasing of AST traversal, and will be fixed.
//
var x: C; // ok
var y = new C(); // error: let ref before decl from value position
class 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; // not an error per se - only if used before init
function f(n: number) {
return n;

View File

@ -183,6 +183,7 @@ var bar1: Bar = new Bar(); // OK
var bar2: Bar = Bar.factory(); // OK
// NB: Don\'t write expected errors using Foo to avoid error collapse hiding an
// unexpected failure in the above code.
var B = class Baz {};
var b = new Baz(); // error: Baz is not a runtime binding in this scope
var C = class Qux {};

View File

@ -89,6 +89,7 @@ function takes_string(_: string) {}
// global write from function
//
var global_x = \"hello\";
function global_f() {}
@ -103,6 +104,7 @@ takes_string(global_x); // error
global_x = 42; // shouldn\'t pollute linear refinement
// local write from function
//
function local_func() {
var local_x = \"hello\";
@ -120,6 +122,7 @@ function local_func() {
// global write from method
//
var global_y = \"hello\";
var global_o = {
@ -136,6 +139,7 @@ takes_string(global_y); // error
global_y = 42; // shouldn\'t pollute linear refinement
// local write from method
//
function local_meth() {
var local_y = \"hello\";

View File

@ -17,6 +17,7 @@ declare module foo {
// This file triggers a violation of the \"disjoint-or-nested ranges invariant\"
// that we implicitly assume in type-at-pos and coverage implementations. In
// particular, when unchecked it causes a crash with coverage --color.
declare module bar {
}
"
@ -65,9 +66,11 @@ declare module foo {
// This file triggers a violation of the \"disjoint-or-nested ranges invariant\"
// that we implicitly assume in type-at-pos and coverage implementations. In
// particular, when unchecked it causes non-termination with coverage --color.
declare module bar {
}
// TODO
declare class qux {}
"
`;

View File

@ -23,6 +23,7 @@ module.exports = B;
var A = require(\"./A\");
//class B extends A { }
module.exports = B;
"
`;

View File

@ -900,6 +900,7 @@ import DefaultD from \"./D\"; // Error: No such module
// ================================================ //
// == CommonJS Clobbering Literal Exports -> ES6 == //
// ================================================ //
import { doesntExist1 } from \"CommonJS_Clobbering_Lit\"; // Error: Not an exported binding
import { numberValue1 } from \"CommonJS_Clobbering_Lit\";
var c1: number = numberValue1;
@ -920,6 +921,7 @@ var f4: string = CJS_Clobb_Lit_NS.default.numberValue5; // Error: number ~> stri
// ============================================== //
// == CommonJS Clobbering Class Exports -> ES6 == //
// ============================================== //
import { doesntExist2 } from \"CommonJS_Clobbering_Class\"; // Error: Not an exported binding
// The following import should error because class statics are not turned into
// named exports for now. This avoids complexities with polymorphic static
@ -941,6 +943,7 @@ var i3: string = new CJS_Clobb_Class_NS.default().instNumber2(); // Error: numbe
// =================================== //
// == CommonJS Named Exports -> ES6 == //
// =================================== //
import { doesntExist3 } from \"CommonJS_Named\"; // Error: Not an exported binding
import { numberValue2 } from \"CommonJS_Named\";
var j1: number = numberValue2;
@ -959,6 +962,7 @@ var m3: string = CJS_Named_NS.numberValue4; // Error: number ~> string
//////////////////////////////
// == ES6 Default -> ES6 == //
//////////////////////////////
import { doesntExist4 } from \"ES6_Default_AnonFunction1\"; // Error: Not an exported binding
import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\";
var n1: number = ES6_Def_AnonFunc1();
@ -972,6 +976,7 @@ var q2: string = new ES6_Def_NamedClass1().givesANum(); // Error: number ~> stri
////////////////////////////
// == ES6 Named -> ES6 == //
////////////////////////////
import doesntExist5 from \"ES6_Named1\"; // Error: Not an exported binding
import { specifierNumber1 as specifierNumber1_1 } from \"ES6_Named1\";
var r1: number = specifierNumber1_1;
@ -1010,6 +1015,7 @@ var ac2: string = numberValue5; // Error: number ~> string
///////////////////////////////////
// == ES6 Default -> CommonJS == //
///////////////////////////////////
require(\"ES6_Default_AnonFunction2\").doesntExist; // Error: \'doesntExist\' isn\'t an export
var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default;
var ad1: number = ES6_Def_AnonFunc2();
@ -1023,6 +1029,7 @@ var ag2: string = new ES6_Def_NamedClass2().givesANum(); // Error: number ~> str
/////////////////////////////////
// == ES6 Named -> CommonJS == //
/////////////////////////////////
var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4;
var ah1: number = specifierNumber4;
var ah2: string = specifierNumber4; // Error: number ~> string
@ -1061,6 +1068,7 @@ var ar2: string = numberValue7; // Error: number ~> string
////////////////////////////////////////////////////////
// == ES6 Default+Named -> ES6 import Default+Named== //
////////////////////////////////////////////////////////
import defaultNum, { str as namedStr } from \"./ES6_DefaultAndNamed\";
var as1: number = defaultNum;
@ -1070,6 +1078,7 @@ var as4: number = namedStr; // Error: string ~> number
////////////////////////////////////////
// == Side-effect only ES6 imports == //
////////////////////////////////////////
import \"./SideEffects\";
//////////////////////////////////////////////

View File

@ -40,6 +40,7 @@ import type { str2 } from \"declare_m_e_with_other_type_declares\";
* \`declare var exports\` is deprecated, so we have a grace period where both
* syntaxes will work.
*/
import DEPRECATED__declare_var_exports from \"DEPRECATED__declare_var_exports\";
(DEPRECATED__declare_var_exports: number);
(DEPRECATED__declare_var_exports: string); // Error: number ~> string

View File

@ -45,6 +45,7 @@ declare module \"declare_m_e_with_other_type_declares\" {
* \`declare var exports\` is deprecated, so we have a grace period where both
* syntaxes will work.
*/
declare module \"DEPRECATED__declare_var_exports\" {
declare var exports: number;
/**

View File

@ -47,6 +47,7 @@ var k4: toz = foo(k1); // works
//////////////////////////////////////////////////////////
// == Declared Module with exports prop (issue 880) == //
////////////////////////////////////////////////////////
import blah from \"foo\";
import type { Foo, Bar, Id } from \"foo\";

View File

@ -16,6 +16,7 @@ function f(x) {
var x = null;
//...
f(x);
"
`;

View File

@ -505,6 +505,7 @@ foo = (i: number) => {
};
// Also make sure that the following doesn\'t loop
declare var o;
var { x: o } = o;
"

View File

@ -75,6 +75,7 @@ exports[`test use_strict_with_flow.js 1`] = `
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\"use strict\";
/* @flow */
(\"\": void); // error
"
`;

View File

@ -1003,6 +1003,7 @@ import DefaultD from \"./D\"; // Error: No such module
// ================================================ //
// == CommonJS Clobbering Literal Exports -> ES6 == //
// ================================================ //
import { doesntExist1 } from \"CommonJS_Clobbering_Lit\"; // Error: Not an exported binding
import { numberValue1 } from \"CommonJS_Clobbering_Lit\";
var c1: number = numberValue1;
@ -1023,6 +1024,7 @@ var f4: string = CJS_Clobb_Lit_NS.default.numberValue5; // Error: number ~> stri
// ============================================== //
// == CommonJS Clobbering Class Exports -> ES6 == //
// ============================================== //
import { doesntExist2 } from \"CommonJS_Clobbering_Class\"; // Error: Not an exported binding
// The following import should error because class statics are not turned into
// named exports for now. This avoids complexities with polymorphic static
@ -1044,6 +1046,7 @@ var i3: string = new CJS_Clobb_Class_NS.default().instNumber2(); // Error: numbe
// =================================== //
// == CommonJS Named Exports -> ES6 == //
// =================================== //
import { doesntExist3 } from \"CommonJS_Named\"; // Error: Not an exported binding
import { numberValue2 } from \"CommonJS_Named\";
var j1: number = numberValue2;
@ -1062,6 +1065,7 @@ var m3: string = CJS_Named_NS.numberValue4; // Error: number ~> string
//////////////////////////////
// == ES6 Default -> ES6 == //
//////////////////////////////
import { doesntExist4 } from \"ES6_Default_AnonFunction1\"; // Error: Not an exported binding
import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\";
var n1: number = ES6_Def_AnonFunc1();
@ -1078,6 +1082,7 @@ var q2: string = new ES6_Def_NamedClass1().givesANum(); // Error: number ~> stri
////////////////////////////
// == ES6 Named -> ES6 == //
////////////////////////////
import doesntExist5 from \"ES6_Named1\"; // Error: Not an exported binding
import { specifierNumber1 as specifierNumber1_1 } from \"ES6_Named1\";
var r1: number = specifierNumber1_1;
@ -1122,6 +1127,7 @@ var ac2: string = numberValue5; // Error: number ~> string
///////////////////////////////////
// == ES6 Default -> CommonJS == //
///////////////////////////////////
require(\"ES6_Default_AnonFunction2\").doesntExist; // Error: \'doesntExist\' isn\'t an export
var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default;
var ad1: number = ES6_Def_AnonFunc2();
@ -1138,6 +1144,7 @@ var ag2: string = new ES6_Def_NamedClass2().givesANum(); // Error: number ~> str
/////////////////////////////////
// == ES6 Named -> CommonJS == //
/////////////////////////////////
var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4;
var ah1: number = specifierNumber4;
var ah2: string = specifierNumber4; // Error: number ~> string
@ -1182,6 +1189,7 @@ var ar2: string = numberValue7; // Error: number ~> string
////////////////////////////////////////////////////////
// == ES6 Default+Named -> ES6 import Default+Named== //
////////////////////////////////////////////////////////
import defaultNum, { str as namedStr } from \"./ES6_DefaultAndNamed\";
var as1: number = defaultNum;
@ -1191,6 +1199,7 @@ var as4: number = namedStr; // Error: string ~> number
////////////////////////////////////////
// == Side-effect only ES6 imports == //
////////////////////////////////////////
import \"./SideEffects\";
//////////////////////////////////////////////
@ -1298,6 +1307,7 @@ CommonJS_Clobbering_Frozen.numberValue1 = 123; // Error: exports are frozen
//
// Requires
//
function testRequires() {
// CommonJS module
var DefaultA = require(\"A\");

View File

@ -275,6 +275,7 @@ new ClassFoo1(); // Error: ClassFoo1 is not a value-identifier
///////////////////////////////////////////////
// == Importing Class Type (Named Export) == //
///////////////////////////////////////////////
import type { ClassFoo2 } from \"./ExportNamed_Class\";
import { foo2Inst } from \"./ExportNamed_Class\";
@ -284,6 +285,7 @@ new ClassFoo2(); // Error: ClassFoo2 is not a value-identifier
/////////////////////////////////////////////////////
// == Importing Class Type (CJS Default Export) == //
/////////////////////////////////////////////////////
import type ClassFoo3T from \"./ExportCJSDefault_Class\";
import ClassFoo3 from \"./ExportCJSDefault_Class\";
var c1: ClassFoo3T = new ClassFoo3();
@ -291,6 +293,7 @@ new ClassFoo3T(); // Error: ClassFoo3 is not a value-identifier
///////////////////////////////////////////////////
// == Importing Class Type (CJS Named Export) == //
///////////////////////////////////////////////////
import type { ClassFoo4, ClassFoo5 } from \"./ExportCJSNamed_Class\";
import { foo4Inst, foo5Inst } from \"./ExportCJSNamed_Class\";
@ -302,6 +305,7 @@ var d3: typeof ClassFoo5 = foo5Inst; // Error: Can\'t typeof a type alias
////////////////////////////////////////////
// == Import Type Alias (Named Export) == //
////////////////////////////////////////////
import type { AliasFoo3 } from \"./ExportNamed_Alias\";
import { givesAFoo3Obj } from \"./ExportNamed_Alias\";
var e1: AliasFoo3 = givesAFoo3Obj();
@ -310,18 +314,22 @@ var e3: typeof AliasFoo3 = givesAFoo3Obj(); // Error: Can\'t typeof a type alias
//////////////////////////////////////////////
// == Import Type Alias (Default Export) == //
//////////////////////////////////////////////
// TODO: No support for this right now. It\'s most likely possible, but it\'s
// unclear how useful it is at the moment and it entails a little
// more work than named type exports, so I\'m punting on it for now.
///////////////////////////////////////////////////////
// == Import Type With Non-Alias Compatible Value == //
///////////////////////////////////////////////////////
import type { numValue } from \"./ExportsANumber\"; // Error: Cannot import-type a number value
////////////////////////////////////////////////////////////////////////
// == Regression Test: https://github.com/facebook/flow/issues/359 == //
// Ensure that type bindings stay type bindings across function body //
// env contexts. //
////////////////////////////////////////////////////////////////////////
import type ClassFoo6 from \"./issue-359\";
function foo() {
ClassFoo6; // Error: Not a value binding

View File

@ -306,6 +306,7 @@ new ClassFoo1T(); // Error: ClassFoo1T is not bound to a value
/////////////////////////////////////////////////
// == Importing Class Typeof (Named Export) == //
/////////////////////////////////////////////////
import typeof { ClassFoo2 as ClassFoo2T } from \"./ExportNamed_Class\";
import { ClassFoo2 } from \"./ExportNamed_Class\";
@ -315,6 +316,7 @@ new ClassFoo2T(); // Error: ClassFoo2T is not bound to a value
///////////////////////////////////////////////////////
// == Importing Class Typeof (CJS Default Export) == //
///////////////////////////////////////////////////////
import typeof ClassFoo3T from \"./ExportCJSDefault_Class\";
import ClassFoo3 from \"./ExportCJSDefault_Class\";
@ -323,6 +325,7 @@ var c2: ClassFoo3T = new ClassFoo3(); // Error: ClassFoo3 (inst) ~> ClassFoo3 (c
/////////////////////////////////////////////////////
// == Importing Class Typeof (CJS Named Export) == //
/////////////////////////////////////////////////////
import typeof { ClassFoo4 as ClassFoo4T } from \"./ExportCJSNamed_Class\";
import { ClassFoo4 } from \"./ExportCJSNamed_Class\";
@ -331,16 +334,20 @@ var d2: ClassFoo4T = new ClassFoo4(); // Error: ClassFoo4 (inst) ~> ClassFoo4 (c
//////////////////////////////////////////////
// == Import Typeof Alias (Named Export) == //
//////////////////////////////////////////////
import typeof { AliasFoo3 } from \"./ExportNamed_Alias\"; // Error: Can\'t \`import typeof\` type aliases!
////////////////////////////////////////////////
// == Import Typeof Alias (Default Export) == //
////////////////////////////////////////////////
// TODO: No support for this right now. It\'s most likely possible, but it\'s
// unclear how useful it is at the moment and it entails a little
// more work than named type exports, so I\'m punting on it for now.
///////////////////////////////////////////////////////////////
// == Import Typeof With Non-Class Value (Default Export) == //
///////////////////////////////////////////////////////////////
import typeof num_default from \"./ExportDefault_Number\";
var f1: num_default = 42;
@ -348,6 +355,7 @@ var f2: num_default = \"asdf\"; // Error: string ~> number
/////////////////////////////////////////////////////////////
// == Import Typeof With Non-Class Value (Named Export) == //
/////////////////////////////////////////////////////////////
import typeof { num as num_named } from \"./ExportNamed_Number\";
var g1: num_named = 42;
@ -355,6 +363,7 @@ var g2: num_named = \"asdf\"; // Error: string ~> number
///////////////////////////////////////////////////////////////////
// == Import Typeof With Non-Class Value (CJS Default Export) == //
///////////////////////////////////////////////////////////////////
import typeof num_cjs_default from \"./ExportCJSDefault_Number\";
var h1: num_cjs_default = 42;
@ -362,6 +371,7 @@ var h2: num_cjs_default = \"asdf\"; // Error: string ~> number
/////////////////////////////////////////////////////////////////
// == Import Typeof With Non-Class Value (CJS Named Export) == //
/////////////////////////////////////////////////////////////////
import typeof { num as num_cjs_named } from \"./ExportCJSNamed_Number\";
var i1: num_cjs_named = 42;
@ -369,6 +379,7 @@ var i2: num_cjs_named = \"asdf\"; // Error: string ~> number
///////////////////////////////////////////////
// == Import Typeof ModuleNamespaceObject == //
///////////////////////////////////////////////
import typeof * as ModuleNSObjT from \"./ExportNamed_Multi\";
var j1: ModuleNSObjT = { num: 42, str: \"asdf\" };
var j2: ModuleNSObjT = { num: 42, str: 42 }; // Error: number ~> string

View File

@ -8,6 +8,7 @@ export type B = string;
// @flow
var A = require(\"./A\");
//import type C from \'./C\';
export type B = string;
"
`;

View File

@ -94,6 +94,7 @@ var k: K = { x: \"\", y: \"\" }; // error: x should be number
declare class C { x: number }
declare class D extends C, Other {} // error: multiple extends
//declare class E implements I { } // parse error
interface A<Y> { y: Y }
interface A_<X> { x: X }
interface B<Z> extends A<string>, A_<Z> { z: Z }

View File

@ -69,6 +69,7 @@ React.createElement(\'bad\', {}); // This is fine
var React = require(\"react\");
// The builtin $JSXIntrinsics should allow any string
var Div = \"div\";
var Bad = \"bad\";
var Str: string = \"str\";

View File

@ -65,11 +65,13 @@ class C {
}
// check
(new C().foo(): boolean); // last wins
(new C().x: boolean); // last wins
(new C().bar: boolean); // last wins
(new C().qux: boolean); // weird outlier where last doesn\'t win in classes
// Objects
const o = {
foo(): number {
return 0;
@ -90,6 +92,7 @@ const o = {
};
// check
(o.foo(): boolean); // last wins
(o.x: boolean); // last wins
(o.bar: boolean); // last wins

View File

@ -37,6 +37,7 @@ var red:string = tuple[indices.red]; // error: tuple[0] is a number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var APIKeys = require(\"./enum\");
// object that maps \"AGE\" to \"age\", \"NAME\" to \"name\"
function foo(x: $Keys<typeof APIKeys>) {}
foo(\"AGE\");
foo(\"LOCATION\"); // error

View File

@ -152,6 +152,7 @@ var x: string = 0;
var x: number = 1;
//declare var T: $Type<number | Array<T>>;
function foo(p: boolean) {}
function sorry(really: boolean) {

View File

@ -27,6 +27,7 @@ var o3 = {};
o3.w = o2;
//declare var exports: { w: any };
module.exports = o3;
"
`;

View File

@ -55,6 +55,7 @@ function foo5<T>(): Array<T> {
var b = foo5();
var y: string = b[0];
*/
var foo6 = function<R>(x: R): R {
return foo1(x);
};

View File

@ -80,6 +80,7 @@ if (y instanceof A) {
y = 0;
}
//f(y);
function bar() {
return true;
}

View File

@ -90,6 +90,7 @@ var App = React.createClass({
var z = this.state.z;
//this.state;
return (
<div>
{foo(x, y)}

View File

@ -392,6 +392,7 @@ import React from \"react\";
//import React from \"React\";
//var React = require(\"react\");
//var React = require(\"React\");
class HelloMessage extends React.Component {
props: { name: string };
}

View File

@ -36,6 +36,7 @@ fs.readFile(\"file.exp\", {}, (_, data) => {
var fs = require(\"fs\");
/* readFile */
fs.readFile(\"file.exp\", (_, data) => {
(data: Buffer);
});
@ -53,6 +54,7 @@ fs.readFile(\"file.exp\", {}, (_, data) => {
});
/* readFileSync */
(fs.readFileSync(\"file.exp\"): Buffer);
(fs.readFileSync(\"file.exp\"): string); // error
(fs.readFileSync(\"file.exp\", \"blah\"): string);

View File

@ -412,6 +412,7 @@ var y = new Foo();
//
// toString
//
// call
takesAString(a.toString());
d.toString(); // ok, even though dict specifies strings, this is a function
@ -450,6 +451,7 @@ takesAString(y.toString());
//
// hasOwnProperty
//
// call
takesABool(a.hasOwnProperty(\"foo\"));
@ -475,6 +477,7 @@ takesABool(y.hasOwnProperty(\"foo\"));
//
// propertyIsEnumerable
//
// call
takesABool(a.propertyIsEnumerable(\"foo\"));
@ -500,6 +503,7 @@ takesABool(y.propertyIsEnumerable(\"foo\"));
//
// valueOf
//
// call
takesAnObject(a.valueOf());
@ -529,6 +533,7 @@ var boolValueOf: boolean = true.valueOf();
//
// toLocaleString
//
// call
takesAString(a.toLocaleString());
@ -554,6 +559,7 @@ takesAString(y.toLocaleString());
//
// constructor
//
var k: Object = a.constructor;
(123).constructor;
"

View File

@ -136,6 +136,7 @@ function is_string_and_number(x, y): %checks {
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
*/
@ -150,6 +151,7 @@ declare function refine_fst<T, P: $Pred<2>>(
): $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;
@ -160,6 +162,7 @@ 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\";
}
@ -343,6 +346,7 @@ var e = refine(a, is_string_regular); // ERROR: is_string_regular is not a
(e: number);
////////////////////////////////////////////////////////////////////////////////
function is_string(x): %checks {
return typeof x === \"string\";
}

View File

@ -388,6 +388,7 @@ 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;

View File

@ -412,6 +412,7 @@ new Promise(function(resolve, reject) {
/////////////////////////////////////////////////
// == Promise constructor reject() function == //
/////////////////////////////////////////////////
// TODO: Promise constructor reject(T) -> catch(T)
new Promise(function(resolve, reject) {
reject(0);
@ -455,6 +456,7 @@ new Promise(function(resolve, reject) {
/////////////////////////////
// == Promise.resolve() == //
/////////////////////////////
// Promise.resolve(T) -> then(T)
Promise.resolve(0).then(function(num) {
var a: number = num;
@ -476,6 +478,7 @@ Promise.resolve(Promise.resolve(Promise.resolve(0))).then(function(num) {
////////////////////////////
// == Promise.reject() == //
////////////////////////////
// TODO: Promise.reject(T) -> catch(T)
Promise.reject(0).catch(function(num) {
var a: number = num;
@ -495,6 +498,7 @@ Promise.reject(Promise.resolve(0)).then(function(num) {
//////////////////////////////////
// == Promise.prototype.then == //
//////////////////////////////////
// resolvedPromise.then():T -> then(T)
Promise
.resolve(0)
@ -544,6 +548,7 @@ Promise
///////////////////////////////////
// == Promise.prototype.catch == //
///////////////////////////////////
// rejectedPromise.catch():U -> then(U)
Promise
.reject(0)

View File

@ -93,12 +93,14 @@ class P<X> {
x: X;
}
// this is like Promise
type Pstar<X> = X | Pstar<P<X>>; // this is like Promise*
var p: P<number> = new P();
(p.x: string); // error
var pstar: Pstar<number> = 0; // OK
(pstar: number); // error, but limit potentially unbounded number of errors!
// e.g., P<number> ~/~ number, P<P<number>> ~/~ number, ...
pstar = p; // OK
(pstar.x: string); // error
pstar = (new P(): P<P<number>>); // OK

View File

@ -543,6 +543,7 @@ var tests = [
// the scope that gets merged after the if statement is the correct
// post-condition scope, not the one that was saved at the beginning of the
// if statement.
function() {
let x: { foo: ?string } = { foo: null };
if (!x.foo) {
@ -1193,6 +1194,7 @@ function foo(a, b, c) {
}
// test refis out of switches that are exhaustive without default case
function exhaustion1(x): number {
var foo;
switch (x) {
@ -1574,6 +1576,7 @@ class A {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var undef_tests = [
// NOTE: not (yet?) supporting non-strict eq test for undefined
// expr !== undefined
function() {
var x: ?string = \"xxx\";
@ -1718,6 +1721,7 @@ class A {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
var void_tests = [
// NOTE: not (yet?) supporting non-strict eq test for undefined
// expr !== void(...)
function() {
var x: ?string = \"xxx\";

View File

@ -668,6 +668,7 @@ function def_assign_within_for(b: boolean, obj: Obj) {
}
// --- name-sensitive havoc ---
type Obj2 = { q: number | string };
function def_assign_setprop_nohavoc(obj: Obj, obj2: Obj2) {
@ -1582,6 +1583,7 @@ function e_array(x: Array<?string>): string {
}
// --- name-sensitive havoc ---
function c2(x: { [key: string]: ?string }, y: { z: string }): string {
if (x[y.z]) {
y.z = \"HEY\";

View File

@ -51,6 +51,7 @@ function f(x: number) {
return x;
}
//function f(x:number):string { return x; }
var x: string = f(0);
module.exports = f;
@ -79,6 +80,7 @@ module.exports = o;
var o = { x: 0 };
//var o: {x: number;} = { x: 0 }
var x: string = o.x;
module.exports = o;

View File

@ -35,6 +35,7 @@ function getNum() {
// $FlowFixMe This was the second loc in the error
var test3: string = getNum(); // This error should be suppressed
// $FlowFixMe Error unused suppression
var test4: string = 123; // This error is NOT suppressed
// $FlowFixMe Indentation shouldn\'t matter
var test5: string = 123; // This error should be suppressed

View File

@ -86,6 +86,7 @@ foo(o2.y); // setting o3.y to 0 has no effect on o2.y
/*
* this bindings:
*/
/* standard functions may rebind this */
function f1(): number {
return this.x;

View File

@ -96,6 +96,7 @@ class B extends A {
}
// covariance checks on this type in invariant positions
class Invariant {
out_object(): { _: this } {
return { _: this };
@ -111,6 +112,7 @@ class Invariant {
}
// covariance checks on this type as type args
class Misc {
// Set<X> has invariant X
out_set(): Set<this> {
@ -483,7 +485,9 @@ class InheritOverride extends Override {}
(new InheritOverride().bar_caller(): InheritOverride); // error
// blame flips below
// Examples with \`this\` types (compare with examples above)
class Base2 {
foo(): this {
return this;
@ -516,6 +520,7 @@ class Override2 extends Base2 {
return new Override2();
} // error (cf. OK above)
// see exploit below
corge(that: this) {} // error
// see exploit below
grault(that: this) {} // error, too

View File

@ -22,6 +22,7 @@ function foo(x: ?string): $NonMaybeType<?string> {
}
//(foo(): string); // should not be necessary to expose the error above
(0: $NonMaybeType<null>); // error
(0: $NonMaybeType<?number>); // ok
(0: $NonMaybeType<number | null>); // ok

View File

@ -22,6 +22,7 @@ module.exports = printBinaryExpression;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\"use babel\";
/* @flow */
/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
@ -29,6 +30,7 @@ module.exports = printBinaryExpression;
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
import type { BinaryExpression } from \"./types\";
function printBinaryExpression(node: BinaryExpression) {
@ -5095,7 +5097,9 @@ export type JSXSpreadAttribute = {
/*
* Flow types for the Babylon AST.
*/
// Abstract types. Something must extend these.
export type Comment =
| {
type: \"CommentLine\",
@ -8277,6 +8281,7 @@ export type Type =
};
// Concrete Types. Nothing can extend these.
export type CommentLine = {
type: \"CommentLine\",
_CommentLine: void,
@ -8302,6 +8307,7 @@ export type CommentBlock = {
};
// Babel concrete types.
export type ArrayExpression = {
type: \"ArrayExpression\",
_ArrayExpression: void,

View File

@ -95,6 +95,7 @@ class MyClass<T> {
var c: MyClass = new MyClass(0); // no error
// no arity error in type annotation using polymorphic class with defaulting
class MyClass2<T, U=string> {
x: T;
y: U;
@ -106,17 +107,21 @@ class MyClass2<T, U=string> {
var c2: MyClass2 = new MyClass2(0, \"\"); // no error
// no arity error in type annotation using polymorphic type alias
type MyObject<T> = { x: T };
var o: MyObject = { x: 0 }; // no error
// arity error in type alias rhs
type MySubobject = { y: number } & MyObject; // no error
// arity error in interface extends
interface MyInterface<T> { x: T }
interface MySubinterface extends MyInterface { y: number } // no error
// no arity error in extends of polymorphic class
class MySubclass
extends MyClass { // ok, type arg inferred
y: number;
@ -126,6 +131,7 @@ class MySubclass
}
// no arity error in call of polymorphic function
function singleton<T>(x: T): Array<T> {
return [x];
}

View File

@ -93,6 +93,7 @@ class MyClass<T> {
var c: MyClass = new MyClass(0); // error, missing argument list (1)
// arity error in type annotation using polymorphic class with defaulting
class MyClass2<T, U=string> {
x: T;
y: U;
@ -104,17 +105,21 @@ class MyClass2<T, U=string> {
var c2: MyClass2 = new MyClass2(0, \"\"); // error, missing argument list (1-2)
// arity error in type annotation using polymorphic type alias
type MyObject<T> = { x: T };
var o: MyObject = { x: 0 }; // error, missing argument list
// arity error in type alias rhs
type MySubobject = { y: number } & MyObject; // error, missing argument list
// arity error in interface extends
interface MyInterface<T> { x: T }
interface MySubinterface extends MyInterface { y: number } // error, missing argument list
// *no* arity error in extends of polymorphic class
class MySubclass
extends MyClass { // ok, type arg inferred
y: number;
@ -124,6 +129,7 @@ class MySubclass
}
// *no* arity error in call of polymorphic function
function singleton<T>(x: T): Array<T> {
return [x];
}

View File

@ -132,6 +132,7 @@ declare class E<T> { m<T>(x: T): E<T> }
declare class F<T> extends E<T> { m<T>(x: T): F<T> }
// Bounds can refer to parent type params (until they are shadowed).
class G<T> {
x: T;
constructor(x: T) {
@ -147,6 +148,7 @@ g.m(0); // ok
g.m(true); // err, bool ~> number|string
(g.m(\"\"): G<number>); // err, string ~> number
// Shadow bounds incompatible with parent
class H<T> {
x: T;
m<T>(x: T) {

View File

@ -107,6 +107,7 @@ var a: MyClass1 = new MyClass1();
// Following tests are errors which conflate the type
// of the class value itself with the type of its
// instances.
// Aside: it\'s worth staring at the following (correct)
// type annotations until they make sense:
//
@ -121,6 +122,7 @@ var a: MyClass1 = new MyClass1();
// The second says that objects produced by the MyClass1
// constructor function have type MyClass1 - the type of
// instances of MyClass1.
// Error: assign the actual MyClass1 value to a variable
// whose annotated type is of instances of MyClass1.
//
@ -141,12 +143,14 @@ var c: typeof MyClass2 = new MyClass2();
//////////////////////////////////////
// == typeof <<non-class value>> == //
//////////////////////////////////////
var numValue: number = 42;
var d: typeof numValue = 100;
var e: typeof numValue = \"asdf\"; // Error: string ~> number
/////////////////////////////////
// == typeof <<type-alias>> == //
/////////////////////////////////
type numberAlias = number;
// This is an error because typeof takes a value, not
@ -159,6 +163,7 @@ var f: typeof numberAlias = 42; // Error: \'typeof <<type-alias>>\' makes no sen
* These provoke a specific error, not just the generic
* \"type is incompatible\"
*/
var Map = { A: \"this is A\", B: \"this is B\", C: \"this is C\" };
var keys: $Keys<Map> = \"A\"; // Error: ineligible value used in type anno
"

View File

@ -327,6 +327,7 @@ function hello(x:X): string {
type X = ({ a: true } & { b: string }) | ({ a: false } & { c: string });
//type X = {a:true, b:string} | {a:false, c:string}; // this works.
function hello(x: X): string {
if (x.a === true) return x.b;
else return x.c;
@ -459,6 +460,7 @@ const obj_result = obj({ x: \"\" }); // currently an error! (expect it to be OK)
// blocks until A1 is partially resolved. Since the argument partially matches
// A1, that branch is selected. Later, that branch errors, but other branches
// have been lost by then.
type A1 = { x: B1 };
type A2 = { x: B2 };
@ -470,6 +472,7 @@ type B2 = string;
///////////////////////////////////////
// similar example with function types
///////////////////////////////////////
function fun(a: A3 | A4) {
return a();
}
@ -487,6 +490,7 @@ type B4 = string;
/////////////////////////////////////////////
// similar example with class instance types
/////////////////////////////////////////////
function inst(a: A5 | A6) {}
class B5 {}
@ -598,6 +602,7 @@ type B1 = string;
///////////////////////////////////////
// similar example with function types
///////////////////////////////////////
function fun(a: (() => number) | (() => string)) {}
fun((() => \"\": A2));
@ -609,6 +614,7 @@ type B2 = string;
/////////////////////////////////////////////////////
// similar example with generic class instance types
/////////////////////////////////////////////////////
class C<X> {}
function inst(a: C<number> | C<string>) {}
@ -622,6 +628,7 @@ type B3 = string;
/////////////////////////////////////////////
// similar example with generic type aliases
/////////////////////////////////////////////
function alias(a: T<number> | T<string>) {}
alias({ x: (x: V<B4>) => {} });
@ -632,6 +639,7 @@ type V<X> = X;
type B4 = string;
// class statics
function stat(a: { x: number } | { x: string }) {}
class D {
@ -643,6 +651,7 @@ stat(D);
type B5 = string;
// tuples
function tup(a: [number, boolean] | [string, boolean]) {}
tup(([\"\", false]: A6));
@ -704,6 +713,7 @@ type B1 = string;
////////////////////////////
// example with array types
////////////////////////////
function arr(a: number[] | string[]) {}
arr(([]: A2));
@ -778,6 +788,7 @@ type B1 = string;
////////////////////////////
// example with array types
////////////////////////////
function arr(a: number[] | string[]) {}
const a2 = ([]: A2);
@ -849,6 +860,7 @@ function fun_call(x: string): string {
/////////////////////////////
// example with array types
/////////////////////////////
function arr(a: number[] | string[]) {}
var a2 = [];
@ -971,6 +983,7 @@ type H2 = number;
///////////////////////////////
// polymorphic recursive types
///////////////////////////////
function polyrec(x: PF<number> | PF<string>) {}
rec({ x: 0 });
@ -1150,6 +1163,7 @@ function id<X>(x: X): X {
/////////////////////////
// primitive annotations
/////////////////////////
function check_prim(_: number | string) {}
// ok
@ -1161,6 +1175,7 @@ check_prim(id(\"\"));
//////////////////////////////
// class instance annotations
//////////////////////////////
class C {}
class D {}
function check_inst(_: C | D) {}
@ -1174,6 +1189,7 @@ check_inst(id(new C()));
////////////////////////
// function annotations
////////////////////////
function check_fun(_: ((_: number) => number) | ((_: string) => string)) {}
// help!
@ -1182,6 +1198,7 @@ check_fun(x => x);
//////////////////////
// object annotations
//////////////////////
function check_obj(_: { x: number } | { x: string }) {}
// ok
@ -1193,6 +1210,7 @@ check_obj({ x: id(\"\") });
/////////////////////
// array annotations
/////////////////////
function check_arr(_: number[] | string[]) {}
// ok
@ -1204,6 +1222,7 @@ check_arr([id(\"\")]);
//////////////////////////////////////
// generic class instance annotations
//////////////////////////////////////
class P<X> {}
function check_poly_inst(_: P<number> | P<string>) {}
@ -1374,6 +1393,7 @@ type EventHandler = (event: Event) => mixed;
type KeyboardEventHandler = (event: KeyboardEvent) => mixed;
// example where globals are not yet resolved
function bar(x: (() => void) | { x: number }) {}
bar(() => {});
@ -1814,6 +1834,7 @@ function hello4(x:X): string {
type X = ({ a: true } & { b: string }) | ({ a: false } & { c: string });
//type X = {a:true, b:string} | {a:false, c:string}; // this works.
function hello1(x: X): string {
if (x.a === true) return x.b;
else return x.c;

View File

@ -35,6 +35,7 @@ function test1(): string {
// regression test for analysis after abnormal control flow:
// consts must not become bot (EmptyT).
function test2() {
const n = 0;