101 lines
2.3 KiB
JavaScript
101 lines
2.3 KiB
JavaScript
/** @flow */
|
|
|
|
// -- types ---
|
|
|
|
// type aliases are hoisted and always available
|
|
|
|
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.
|
|
// - allow forward refs to lets from type positions.
|
|
//
|
|
// currently we're too lenient about TDZ in closures -
|
|
// from value positions, we currently enforce TDZ only in-scope.
|
|
// this is unsound - a let or const may remain uninitialized when
|
|
// 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;
|
|
const c = 0;
|
|
}
|
|
|
|
function f1(b) {
|
|
x = 10; // error, attempt to write to let before decl
|
|
let x = 0;
|
|
if (b) {
|
|
y = 10; // error, attempt to write to let before decl
|
|
let y = 0;
|
|
}
|
|
}
|
|
|
|
function f2() {
|
|
{
|
|
var v = x * c; // errors, let + const referenced before decl
|
|
}
|
|
let x = 0;
|
|
const c = 0;
|
|
}
|
|
|
|
// functions are let-scoped and hoisted
|
|
function f3() {
|
|
var s: string = foo(); // ok, finds hoisted outer
|
|
{
|
|
var n: number = foo(); // ok, finds hoisted inner
|
|
function foo() { return 0; }
|
|
}
|
|
var s2: string = foo(); // ok, hoisted outer not clobbered
|
|
function foo() { return ""; }
|
|
}
|
|
|
|
// out-of-scope TDZ not enforced. sometimes right...
|
|
function f4() {
|
|
function g() { return x + c; } // ok, g doesn't run in TDZ
|
|
let x = 0;
|
|
const c = 0;
|
|
}
|
|
|
|
// ...sometimes wrong
|
|
function f5() {
|
|
function g() { return x; }
|
|
g(); // should error, but doesn't currently
|
|
let x = 0;
|
|
const c = 0;
|
|
}
|
|
|
|
// - from type positions, we currently error on forward refs to any
|
|
// value (i.e., class or function). this is a basic flaw in our
|
|
// phasing of AST traversal, and will be fixed.
|
|
//
|
|
|
|
var x: C; // 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; }
|
|
|
|
f(a); // error: undefined ~/> number
|
|
|
|
a = 10;
|
|
|
|
f(a); // ok, a: number (not ?number)
|