I find it weird to put `{}` together. So I figured I would change it to have an empty line and ask for feedback :)

Beware: most of the test cases are not representative of real code, you almost never define blocks with no content in practice.
916 lines
17 KiB
Plaintext
916 lines
17 KiB
Plaintext
exports[`test const.js 1`] = `
|
|
"const x = 0;
|
|
|
|
// errors: const cannot be reassigned
|
|
x++;
|
|
x--;
|
|
x += 0;
|
|
x -= 0;
|
|
x /= 0;
|
|
x %= 0;
|
|
x <<= 0
|
|
x >>= 0;
|
|
x >>>= 0;
|
|
x |= 0;
|
|
x ^= 0;
|
|
x &= 0;
|
|
|
|
// regression tests -- OK to assign consts like this:
|
|
|
|
const { foo } = { foo: \"foo\" }
|
|
const [ bar ] = [\"bar\"];
|
|
(foo: number); // error: string ~> number
|
|
(bar: number); // error: string ~> number
|
|
|
|
declare var bazzes: { baz: string }[];
|
|
for (const { baz } of bazzes) {
|
|
(baz: number); // error: string ~> number
|
|
}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
const x = 0;
|
|
|
|
// errors: const cannot be reassigned
|
|
x++;
|
|
x--;
|
|
x += 0;
|
|
x -= 0;
|
|
x /= 0;
|
|
x %= 0;
|
|
x <<= 0;
|
|
x >>= 0;
|
|
x >>>= 0;
|
|
x |= 0;
|
|
x ^= 0;
|
|
x &= 0;
|
|
|
|
// regression tests -- OK to assign consts like this:
|
|
const { foo } = { foo: \"foo\" };
|
|
const [ bar ] = [ \"bar\" ];
|
|
(foo: number);
|
|
// error: string ~> number
|
|
(bar: number);
|
|
// error: string ~> number
|
|
declare var bazzes: { baz: string }[];
|
|
for (const { baz } of bazzes) {
|
|
(baz: number); // error: string ~> number
|
|
}
|
|
"
|
|
`;
|
|
|
|
exports[`test rebinding.js 1`] = `
|
|
"/* @flow
|
|
* test errors on illegal rebinding/reassignment
|
|
*
|
|
* type class let const var (reassign)
|
|
* type x x x x x x
|
|
* class x x x x x
|
|
* let x x x x x
|
|
* const x x x x x x
|
|
* var x x x x
|
|
*/
|
|
|
|
// type x *
|
|
|
|
function type_type() {
|
|
type A = number;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function type_class() {
|
|
type A = number;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function type_let() {
|
|
type A = number;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function type_const() {
|
|
type A = number;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function type_var() {
|
|
type A = number;
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
function type_reassign() {
|
|
type A = number;
|
|
A = 42; // error: type alias ref\'d from value pos
|
|
}
|
|
|
|
// class x *
|
|
|
|
function class_type() {
|
|
class A {}
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function class_class() {
|
|
class A {}
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function class_let() {
|
|
class A {}
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function class_const() {
|
|
class A {}
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function class_var() {
|
|
class A {}
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
// let x *
|
|
|
|
function let_type() {
|
|
let A = 0;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function let_class() {
|
|
let A = 0;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function let_let() {
|
|
let A = 0;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function let_const() {
|
|
let A = 0;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function let_var() {
|
|
let A = 0;
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
// const x *
|
|
|
|
function const_type() {
|
|
const A = 0;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function const_class() {
|
|
const A = 0;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function const_let() {
|
|
const A = 0;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function const_const() {
|
|
const A = 0;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function const_var() {
|
|
const A = 0;
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
function const_reassign() {
|
|
const A = 0;
|
|
A = 42; // error: cannot be reassigned
|
|
}
|
|
|
|
// var x *
|
|
|
|
function var_type() {
|
|
var A = 0;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function var_class() {
|
|
var A = 0;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function var_let() {
|
|
var A = 0;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function var_const() {
|
|
var A = 0;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function var_var() {
|
|
var A = 0;
|
|
var A = 0; // OK
|
|
}
|
|
|
|
// function x *
|
|
|
|
function function_toplevel() {
|
|
function a() {};
|
|
function a() {}; // OK
|
|
}
|
|
|
|
function function_block() {
|
|
{
|
|
function a() {};
|
|
function a() {}; // error: name already bound
|
|
}
|
|
}
|
|
|
|
// corner cases
|
|
|
|
function var_shadow_nested_scope() {
|
|
{
|
|
let x = 0;
|
|
{
|
|
var x = 0; // error: name already bound
|
|
}
|
|
}
|
|
}
|
|
|
|
function type_shadow_nested_scope() {
|
|
{
|
|
let x = 0;
|
|
{
|
|
type x = string; // error: name already bound
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
var y = 0; // OK
|
|
}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
/* @flow
|
|
* test errors on illegal rebinding/reassignment
|
|
*
|
|
* type class let const var (reassign)
|
|
* type x x x x x x
|
|
* class x x x x x
|
|
* let x x x x x
|
|
* const x x x x x x
|
|
* var x x x x
|
|
*/
|
|
|
|
// type x *
|
|
|
|
function type_type() {
|
|
type A = number;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function type_class() {
|
|
type A = number;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function type_let() {
|
|
type A = number;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function type_const() {
|
|
type A = number;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function type_var() {
|
|
type A = number;
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
function type_reassign() {
|
|
type A = number;
|
|
A = 42; // error: type alias ref\'d from value pos
|
|
}
|
|
|
|
// class x *
|
|
function class_type() {
|
|
class A {}
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function class_class() {
|
|
class A {}
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function class_let() {
|
|
class A {}
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function class_const() {
|
|
class A {}
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function class_var() {
|
|
class A {}
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
// let x *
|
|
function let_type() {
|
|
let A = 0;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function let_class() {
|
|
let A = 0;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function let_let() {
|
|
let A = 0;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function let_const() {
|
|
let A = 0;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function let_var() {
|
|
let A = 0;
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
// const x *
|
|
function const_type() {
|
|
const A = 0;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function const_class() {
|
|
const A = 0;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function const_let() {
|
|
const A = 0;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function const_const() {
|
|
const A = 0;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function const_var() {
|
|
const A = 0;
|
|
var A = 0; // error: name already bound
|
|
}
|
|
|
|
function const_reassign() {
|
|
const A = 0;
|
|
A = 42; // error: cannot be reassigned
|
|
}
|
|
|
|
// var x *
|
|
function var_type() {
|
|
var A = 0;
|
|
type A = number; // error: name already bound
|
|
}
|
|
|
|
function var_class() {
|
|
var A = 0;
|
|
class A {} // error: name already bound
|
|
}
|
|
|
|
function var_let() {
|
|
var A = 0;
|
|
let A = 0; // error: name already bound
|
|
}
|
|
|
|
function var_const() {
|
|
var A = 0;
|
|
const A = 0; // error: name already bound
|
|
}
|
|
|
|
function var_var() {
|
|
var A = 0;
|
|
var A = 0; // OK
|
|
}
|
|
|
|
// function x *
|
|
function function_toplevel() {
|
|
function a() {
|
|
}
|
|
|
|
function a() {
|
|
}
|
|
}
|
|
|
|
function function_block() {
|
|
{
|
|
function a() {
|
|
}
|
|
|
|
function a() {
|
|
}
|
|
}
|
|
}
|
|
|
|
// corner cases
|
|
function var_shadow_nested_scope() {
|
|
{
|
|
let x = 0;
|
|
{
|
|
var x = 0; // error: name already bound
|
|
}
|
|
}
|
|
}
|
|
|
|
function type_shadow_nested_scope() {
|
|
{
|
|
let x = 0;
|
|
{
|
|
type x = string; // error: name already bound
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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
|
|
var y = 0; // OK
|
|
}
|
|
"
|
|
`;
|
|
|
|
exports[`test scope.js 1`] = `
|
|
"function block_scope() {
|
|
let a: number = 0;
|
|
var b: number = 0;
|
|
{
|
|
let a = \"\"; // ok: local to block
|
|
var b = \"\"; // error: string ~> number
|
|
}
|
|
}
|
|
|
|
function switch_scope(x: string) {
|
|
let a: number = 0;
|
|
var b: number = 0;
|
|
switch (x) {
|
|
case \"foo\":
|
|
let a = \"\"; // ok: local to switch
|
|
var b = \"\"; // error: string ~> number
|
|
break;
|
|
case \"bar\":
|
|
let a = \"\"; // error: a already bound in switch
|
|
break;
|
|
}
|
|
}
|
|
|
|
// a switch is a single lexical scope, so lets and non-disjoint
|
|
// cases can mix in odd ways. our support for edge cases is not
|
|
// yet perfect.
|
|
function switch_scope2(x: number) {
|
|
switch (x) {
|
|
case 0:
|
|
a = \"\"; // error: assign before declaration
|
|
break;
|
|
case 1:
|
|
var b = a; // error: use before declaration
|
|
break;
|
|
case 2:
|
|
let a = \"\";
|
|
break;
|
|
case 3:
|
|
a = \"\"; // error: skipped initializer
|
|
break;
|
|
case 4:
|
|
var c:string = a; // error: skipped initializer
|
|
break;
|
|
}
|
|
a = \"\"; // error: a no longer in scope
|
|
}
|
|
|
|
function try_scope() {
|
|
let a: number = 0;
|
|
try {
|
|
let a = \"\"; // ok
|
|
} catch (e) {
|
|
let a = \"\"; // ok
|
|
} finally {
|
|
let a = \"\"; // ok
|
|
}
|
|
}
|
|
|
|
function for_scope_let() {
|
|
let a: number = 0;
|
|
for (let a = \"\" /* ok: local to init */;;) {}
|
|
}
|
|
|
|
function for_scope_var() {
|
|
var a: number = 0;
|
|
for (var a = \"\" /* error: string ~> number */;;) {}
|
|
}
|
|
|
|
function for_in_scope_let(o: Object) {
|
|
let a: number = 0;
|
|
for (let a /* ok: local to init */ in o) {}
|
|
}
|
|
|
|
function for_in_scope_var(o: Object) {
|
|
var a: number = 0;
|
|
for (var a /* error: string ~> number */ in o) {}
|
|
}
|
|
|
|
function for_of_scope_let(xs: string[]) {
|
|
let a: number = 0;
|
|
for (let a /* ok: local to init */ of xs) {}
|
|
}
|
|
|
|
function for_of_scope_var(xs: string[]) {
|
|
var a: number = 0;
|
|
for (var a /* error: string ~> number */ of xs) {}
|
|
}
|
|
|
|
function default_param_1() {
|
|
// function binding in scope in default expr
|
|
function f(
|
|
x: () => string = f // error: number ~> string
|
|
): number {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function default_param_2() {
|
|
// fn body bindings not visible from param scope
|
|
let a = \"\";
|
|
function f0(x = () => a): number {
|
|
let a = 0;
|
|
return x(); // error: string ~> number
|
|
}
|
|
function f1(x = b /* error: cannot resolve b */): number {
|
|
let b = 0;
|
|
return x;
|
|
}
|
|
}
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
function block_scope() {
|
|
let a: number = 0;
|
|
var b: number = 0;
|
|
{
|
|
let a = \"\";
|
|
// ok: local to block
|
|
var b = \"\"; // error: string ~> number
|
|
}
|
|
}
|
|
|
|
function switch_scope(x: string) {
|
|
let a: number = 0;
|
|
var b: number = 0;
|
|
switch (x) {
|
|
case \"foo\":
|
|
let a = \"\";
|
|
// ok: local to switch
|
|
var b = \"\";
|
|
// error: string ~> number
|
|
break;
|
|
case \"bar\":
|
|
let a = \"\";
|
|
// error: a already bound in switch
|
|
break;
|
|
}
|
|
}
|
|
|
|
// a switch is a single lexical scope, so lets and non-disjoint
|
|
// cases can mix in odd ways. our support for edge cases is not
|
|
// yet perfect.
|
|
function switch_scope2(x: number) {
|
|
switch (x) {
|
|
case 0:
|
|
a = \"\";
|
|
// error: assign before declaration
|
|
break;
|
|
case 1:
|
|
var b = a;
|
|
// error: use before declaration
|
|
break;
|
|
case 2:
|
|
let a = \"\";
|
|
break;
|
|
case 3:
|
|
a = \"\";
|
|
// error: skipped initializer
|
|
break;
|
|
case 4:
|
|
var c: string = a;
|
|
// error: skipped initializer
|
|
break;
|
|
}
|
|
a = \"\"; // error: a no longer in scope
|
|
}
|
|
|
|
function try_scope() {
|
|
let a: number = 0;
|
|
try {
|
|
let a = \"\"; // ok
|
|
} catch (e) {
|
|
let a = \"\"; // ok
|
|
} finally {
|
|
let a = \"\"; // ok
|
|
}
|
|
}
|
|
|
|
function for_scope_let() {
|
|
let a: number = 0;
|
|
for (let a = \"\" /* ok: local to init */; ; ) {
|
|
}
|
|
}
|
|
|
|
function for_scope_var() {
|
|
var a: number = 0;
|
|
for (var a = \"\" /* error: string ~> number */; ; ) {
|
|
}
|
|
}
|
|
|
|
function for_in_scope_let(o: Object) {
|
|
let a: number = 0;
|
|
for (let a /* ok: local to init */ in o) {
|
|
}
|
|
}
|
|
|
|
function for_in_scope_var(o: Object) {
|
|
var a: number = 0;
|
|
for (var a /* error: string ~> number */ in o) {
|
|
}
|
|
}
|
|
|
|
function for_of_scope_let(xs: string[]) {
|
|
let a: number = 0;
|
|
for (let a /* ok: local to init */ of xs) {
|
|
}
|
|
}
|
|
|
|
function for_of_scope_var(xs: string[]) {
|
|
var a: number = 0;
|
|
for (var a /* error: string ~> number */ of xs) {
|
|
}
|
|
}
|
|
|
|
function default_param_1() {
|
|
// function binding in scope in default expr
|
|
function f(
|
|
// error: number ~> string
|
|
x: () => string = f
|
|
): number {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
function default_param_2() {
|
|
// fn body bindings not visible from param scope
|
|
let a = \"\";
|
|
function f0(x = () => a): number {
|
|
let a = 0;
|
|
return x(); // error: string ~> number
|
|
}
|
|
function f1(x = b /* error: cannot resolve b */): number {
|
|
let b = 0;
|
|
return x;
|
|
}
|
|
}
|
|
"
|
|
`;
|
|
|
|
exports[`test tdz.js 1`] = `
|
|
"/** @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)
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
/** @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)
|
|
"
|
|
`;
|