// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`all.js 1`] = `
====================================options=====================================
parsers: ["flow"]
printWidth: 80
                                                                                | printWidth
=====================================input======================================
// @flow

declare var pstr: Promise<string>;
declare var pnum: Promise<number>;

Promise.all([
  pstr,
  pnum,
  true, // non-Promise values passed through
]).then((xs) => {
  // tuple information is preserved
  let [a,b,c] = xs;
  (a: number);  // Error: string ~> number
  (b: boolean); // Error: number ~> boolean
  (c: string);  // Error: boolean ~> string

  // array element type is (string | number | boolean)
  xs.forEach(x => {
    (x: void);  // Errors: string ~> void, number ~> void, boolean ~> void
  });
});

// First argument is required
Promise.all(); // Error: expected array instead of undefined (too few arguments)

// Mis-typed arg
Promise.all(0); // Error: expected array instead of number

// Promise.all is a function
(Promise.all : Function);

// Promise.all supports iterables
function test(val: Iterable<Promise<number>>) {
  const r: Promise<Array<number>> = Promise.all(val);
}

function tes2(val: Map<string, Promise<number>>) {
  const r: Promise<Array<number>> = Promise.all(val.values());
}

=====================================output=====================================
// @flow

declare var pstr: Promise<string>;
declare var pnum: Promise<number>;

Promise.all([
  pstr,
  pnum,
  true // non-Promise values passed through
]).then(xs => {
  // tuple information is preserved
  let [a, b, c] = xs;
  (a: number); // Error: string ~> number
  (b: boolean); // Error: number ~> boolean
  (c: string); // Error: boolean ~> string

  // array element type is (string | number | boolean)
  xs.forEach(x => {
    (x: void); // Errors: string ~> void, number ~> void, boolean ~> void
  });
});

// First argument is required
Promise.all(); // Error: expected array instead of undefined (too few arguments)

// Mis-typed arg
Promise.all(0); // Error: expected array instead of number

// Promise.all is a function
(Promise.all: Function);

// Promise.all supports iterables
function test(val: Iterable<Promise<number>>) {
  const r: Promise<Array<number>> = Promise.all(val);
}

function tes2(val: Map<string, Promise<number>>) {
  const r: Promise<Array<number>> = Promise.all(val.values());
}

================================================================================
`;

exports[`covariance.js 1`] = `
====================================options=====================================
parsers: ["flow"]
printWidth: 80
                                                                                | printWidth
=====================================input======================================
/* @flow */

async function testAll() {
  /* This is a test case from https://github.com/facebook/flow/issues/1143
   * which was previously an error due to Array's invariance and an improper
   * definition of Promise.all */
    const x: Array<Promise<?string>> = [];
    const y: Promise<Array<?string>> = Promise.all(x);
    const z: Array<?string> = await y;
}

async function testRace() {
    const x: Array<Promise<?string>> = [];
    const y: Promise<?string> = Promise.race(x);
    const z: ?string = await y;
}

=====================================output=====================================
/* @flow */

async function testAll() {
  /* This is a test case from https://github.com/facebook/flow/issues/1143
   * which was previously an error due to Array's invariance and an improper
   * definition of Promise.all */
  const x: Array<Promise<?string>> = [];
  const y: Promise<Array<?string>> = Promise.all(x);
  const z: Array<?string> = await y;
}

async function testRace() {
  const x: Array<Promise<?string>> = [];
  const y: Promise<?string> = Promise.race(x);
  const z: ?string = await y;
}

================================================================================
`;

exports[`promise.js 1`] = `
====================================options=====================================
parsers: ["flow"]
printWidth: 80
                                                                                | printWidth
=====================================input======================================
/**
 * @flow
 */

//////////////////////////////////////////////////
// == Promise constructor resolve() function == //
//////////////////////////////////////////////////

// Promise constructor resolve(T) -> then(T)
new Promise(function(resolve, reject) {
  resolve(0);
}).then(function(num) {
  var a: number = num;

  // TODO: The error message that results from this is almost useless
  var b: string = num; // Error: number ~> string
});

// Promise constructor with arrow function resolve(T) -> then(T)
new Promise((resolve, reject) => resolve(0))
  .then(function(num) {
    var a: number = num;

    // TODO: The error message that results from this is almost useless
    var b: string = num; // Error: number ~> string
  });

// Promise constructor resolve(Promise<T>) -> then(T)
new Promise(function(resolve, reject) {
  resolve(new Promise(function(resolve, reject) {
    resolve(0);
  }));
}).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise constructor resolve(Promise<Promise<T>>) -> then(T)
new Promise(function(resolve, reject) {
  resolve(new Promise(function(resolve, reject) {
    resolve(new Promise(function(resolve, reject) {
      resolve(0);
    }));
  }));
}).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise constructor resolve(T); resolve(U); -> then(T|U)
new Promise(function(resolve, reject) {
  if (Math.random()) {
    resolve(42);
  } else {
    resolve('str');
  }
}).then(function(numOrStr) {
  if (typeof numOrStr === 'string') {
    var a: string = numOrStr;
  } else {
    var b: number = numOrStr;
  }
  var c: string = numOrStr; // Error: number|string -> string
});

/////////////////////////////////////////////////
// == Promise constructor reject() function == //
/////////////////////////////////////////////////

// TODO: Promise constructor reject(T) -> catch(T)
new Promise(function(resolve, reject) {
  reject(0);
}).catch(function(num) {
  var a: number = num;

  // TODO
  var b: string = num; // Error: number ~> string
});

// TODO: Promise constructor reject(Promise<T>) ~> catch(Promise<T>)
new Promise(function(resolve, reject) {
  reject(new Promise(function(resolve, reject) {
    reject(0);
  }));
}).catch(function(num) {
  var a: Promise<number> = num;

  // TODO
  var b: number = num; // Error: Promise<Number> ~> number
});

// TODO: Promise constructor reject(T); reject(U); -> then(T|U)
new Promise(function(resolve, reject) {
  if (Math.random()) {
    reject(42);
  } else {
    reject('str');
  }
}).catch(function(numOrStr) {
  if (typeof numOrStr === 'string') {
    var a: string = numOrStr;
  } else {
    var b: number = numOrStr;
  }

  // TODO
  var c: string = numOrStr; // Error: number|string -> string
});

/////////////////////////////
// == Promise.resolve() == //
/////////////////////////////

// Promise.resolve(T) -> then(T)
Promise.resolve(0).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise.resolve(Promise<T>) -> then(T)
Promise.resolve(Promise.resolve(0)).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise.resolve(Promise<Promise<T>>) -> then(T)
Promise.resolve(Promise.resolve(Promise.resolve(0))).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

////////////////////////////
// == Promise.reject() == //
////////////////////////////

// TODO: Promise.reject(T) -> catch(T)
Promise.reject(0).catch(function(num) {
  var a: number = num;

  // TODO
  var b: string = num; // Error: number ~> string
});

// TODO: Promise.reject(Promise<T>) -> catch(Promise<T>)
Promise.reject(Promise.resolve(0)).then(function(num) {
  var a: Promise<number> = num;

  // TODO
  var b: number = num; // Error: Promise<number> ~> number
});

//////////////////////////////////
// == Promise.prototype.then == //
//////////////////////////////////

// resolvedPromise.then():T -> then(T)
Promise.resolve(0)
  .then(function(num) { return 'asdf'; })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// resolvedPromise.then():Promise<T> -> then(T)
Promise.resolve(0)
  .then(function(num) { return Promise.resolve('asdf'); })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// resolvedPromise.then():Promise<Promise<T>> -> then(T)
Promise.resolve(0)
  .then(function(num) { return Promise.resolve(Promise.resolve('asdf')); })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// TODO: resolvedPromise.then(<throw(T)>) -> catch(T)
Promise.resolve(0)
  .then(function(num) {
    throw 'str';
  })
  .catch(function(str) {
    var a: string = str;

    // TODO
    var b: number = str; // Error: string ~> number
  });

///////////////////////////////////
// == Promise.prototype.catch == //
///////////////////////////////////

// rejectedPromise.catch():U -> then(U)
Promise.reject(0)
  .catch(function(num) { return 'asdf'; })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// rejectedPromise.catch():Promise<U> -> then(U)
Promise.reject(0)
  .catch(function(num) { return Promise.resolve('asdf'); })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// rejectedPromise.catch():Promise<Promise<U>> -> then(U)
Promise.reject(0)
  .catch(function(num) { return Promise.resolve(Promise.resolve('asdf')); })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// resolvedPromise<T> -> catch() -> then():?T
Promise.resolve(0)
  .catch(function(err) {})
  .then(function(num) {
    var a: ?number = num;
    var b: string = num; // Error: string ~> number
  });

=====================================output=====================================
/**
 * @flow
 */

//////////////////////////////////////////////////
// == Promise constructor resolve() function == //
//////////////////////////////////////////////////

// Promise constructor resolve(T) -> then(T)
new Promise(function(resolve, reject) {
  resolve(0);
}).then(function(num) {
  var a: number = num;

  // TODO: The error message that results from this is almost useless
  var b: string = num; // Error: number ~> string
});

// Promise constructor with arrow function resolve(T) -> then(T)
new Promise((resolve, reject) => resolve(0)).then(function(num) {
  var a: number = num;

  // TODO: The error message that results from this is almost useless
  var b: string = num; // Error: number ~> string
});

// Promise constructor resolve(Promise<T>) -> then(T)
new Promise(function(resolve, reject) {
  resolve(
    new Promise(function(resolve, reject) {
      resolve(0);
    })
  );
}).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise constructor resolve(Promise<Promise<T>>) -> then(T)
new Promise(function(resolve, reject) {
  resolve(
    new Promise(function(resolve, reject) {
      resolve(
        new Promise(function(resolve, reject) {
          resolve(0);
        })
      );
    })
  );
}).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise constructor resolve(T); resolve(U); -> then(T|U)
new Promise(function(resolve, reject) {
  if (Math.random()) {
    resolve(42);
  } else {
    resolve("str");
  }
}).then(function(numOrStr) {
  if (typeof numOrStr === "string") {
    var a: string = numOrStr;
  } else {
    var b: number = numOrStr;
  }
  var c: string = numOrStr; // Error: number|string -> string
});

/////////////////////////////////////////////////
// == Promise constructor reject() function == //
/////////////////////////////////////////////////

// TODO: Promise constructor reject(T) -> catch(T)
new Promise(function(resolve, reject) {
  reject(0);
}).catch(function(num) {
  var a: number = num;

  // TODO
  var b: string = num; // Error: number ~> string
});

// TODO: Promise constructor reject(Promise<T>) ~> catch(Promise<T>)
new Promise(function(resolve, reject) {
  reject(
    new Promise(function(resolve, reject) {
      reject(0);
    })
  );
}).catch(function(num) {
  var a: Promise<number> = num;

  // TODO
  var b: number = num; // Error: Promise<Number> ~> number
});

// TODO: Promise constructor reject(T); reject(U); -> then(T|U)
new Promise(function(resolve, reject) {
  if (Math.random()) {
    reject(42);
  } else {
    reject("str");
  }
}).catch(function(numOrStr) {
  if (typeof numOrStr === "string") {
    var a: string = numOrStr;
  } else {
    var b: number = numOrStr;
  }

  // TODO
  var c: string = numOrStr; // Error: number|string -> string
});

/////////////////////////////
// == Promise.resolve() == //
/////////////////////////////

// Promise.resolve(T) -> then(T)
Promise.resolve(0).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise.resolve(Promise<T>) -> then(T)
Promise.resolve(Promise.resolve(0)).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

// Promise.resolve(Promise<Promise<T>>) -> then(T)
Promise.resolve(Promise.resolve(Promise.resolve(0))).then(function(num) {
  var a: number = num;
  var b: string = num; // Error: number ~> string
});

////////////////////////////
// == Promise.reject() == //
////////////////////////////

// TODO: Promise.reject(T) -> catch(T)
Promise.reject(0).catch(function(num) {
  var a: number = num;

  // TODO
  var b: string = num; // Error: number ~> string
});

// TODO: Promise.reject(Promise<T>) -> catch(Promise<T>)
Promise.reject(Promise.resolve(0)).then(function(num) {
  var a: Promise<number> = num;

  // TODO
  var b: number = num; // Error: Promise<number> ~> number
});

//////////////////////////////////
// == Promise.prototype.then == //
//////////////////////////////////

// resolvedPromise.then():T -> then(T)
Promise.resolve(0)
  .then(function(num) {
    return "asdf";
  })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// resolvedPromise.then():Promise<T> -> then(T)
Promise.resolve(0)
  .then(function(num) {
    return Promise.resolve("asdf");
  })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// resolvedPromise.then():Promise<Promise<T>> -> then(T)
Promise.resolve(0)
  .then(function(num) {
    return Promise.resolve(Promise.resolve("asdf"));
  })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// TODO: resolvedPromise.then(<throw(T)>) -> catch(T)
Promise.resolve(0)
  .then(function(num) {
    throw "str";
  })
  .catch(function(str) {
    var a: string = str;

    // TODO
    var b: number = str; // Error: string ~> number
  });

///////////////////////////////////
// == Promise.prototype.catch == //
///////////////////////////////////

// rejectedPromise.catch():U -> then(U)
Promise.reject(0)
  .catch(function(num) {
    return "asdf";
  })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// rejectedPromise.catch():Promise<U> -> then(U)
Promise.reject(0)
  .catch(function(num) {
    return Promise.resolve("asdf");
  })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// rejectedPromise.catch():Promise<Promise<U>> -> then(U)
Promise.reject(0)
  .catch(function(num) {
    return Promise.resolve(Promise.resolve("asdf"));
  })
  .then(function(str) {
    var a: string = str;
    var b: number = str; // Error: string ~> number
  });

// resolvedPromise<T> -> catch() -> then():?T
Promise.resolve(0)
  .catch(function(err) {})
  .then(function(num) {
    var a: ?number = num;
    var b: string = num; // Error: string ~> number
  });

================================================================================
`;

exports[`resolve_global.js 1`] = `
====================================options=====================================
parsers: ["flow"]
printWidth: 80
                                                                                | printWidth
=====================================input======================================
/**
 * test Promise name resolution
 * @flow
 */

/**
 * 1. introduce shadowing bindings for important names
 */
class Promise {}

/**
 * 2. implicit refs to Promise during desugaring should be unaffected
 */
async function foo(x: boolean) {
  if (x) {
    return {bar: 'baz'};
  } else {
    return null;
  }
}

async function run() {
  console.log(await foo(true));
  console.log(await foo(false));
}

run();

/**
 * 3. but explicit name refs from code and annos resolve
 * using the usual rules
 */
// error: \`Promise\` in return expr is the local binding
async function bar() {
  return Promise.resolve(0);
}

// error: return type anno is a ref to the local binding
async function baz(): Promise<number> {
  return 0;
}

=====================================output=====================================
/**
 * test Promise name resolution
 * @flow
 */

/**
 * 1. introduce shadowing bindings for important names
 */
class Promise {}

/**
 * 2. implicit refs to Promise during desugaring should be unaffected
 */
async function foo(x: boolean) {
  if (x) {
    return { bar: "baz" };
  } else {
    return null;
  }
}

async function run() {
  console.log(await foo(true));
  console.log(await foo(false));
}

run();

/**
 * 3. but explicit name refs from code and annos resolve
 * using the usual rules
 */
// error: \`Promise\` in return expr is the local binding
async function bar() {
  return Promise.resolve(0);
}

// error: return type anno is a ref to the local binding
async function baz(): Promise<number> {
  return 0;
}

================================================================================
`;

exports[`resolve_void.js 1`] = `
====================================options=====================================
parsers: ["flow"]
printWidth: 80
                                                                                | printWidth
=====================================input======================================
// @flow

(Promise.resolve(): Promise<number>); // error

(Promise.resolve(undefined): Promise<number>); // error

=====================================output=====================================
// @flow

(Promise.resolve(): Promise<number>); // error

(Promise.resolve(undefined): Promise<number>); // error

================================================================================
`;
