Index: test/mjsunit/harmony/typesystem/ambient-declarations.js |
diff --git a/test/mjsunit/harmony/typesystem/ambient-declarations.js b/test/mjsunit/harmony/typesystem/ambient-declarations.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..47b3e63689c58ffa76c2850a102df7e9ec36b799 |
--- /dev/null |
+++ b/test/mjsunit/harmony/typesystem/ambient-declarations.js |
@@ -0,0 +1,229 @@ |
+// Copyright 2016 the V8 project authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+// Flags: --harmony-types |
+ |
+ |
+load("test/mjsunit/harmony/typesystem/testgen.js"); |
+ |
+ |
+function CheckValidAmbient(decl, full, preamble) { |
+ preamble = typeof(preamble) === "undefined" ? '' : preamble + '; '; |
+ CheckValid(preamble + "declare " + decl); |
+ if (typeof(full) === "undefined") full = decl; |
+ if (typeof(full) === "null") return; |
+ CheckValid(preamble + "declare " + decl + "; " + full); |
+} |
+ |
+function CheckInvalidAmbient(decl, full=null, preamble) { |
+ preamble = typeof(preamble) === "undefined" ? '' : preamble + '; '; |
+ CheckInvalid(preamble + "declare " + decl); |
+ if (typeof(full) === "undefined") full = decl; |
+ if (typeof(full) === "null") return; |
+ CheckInvalid(preamble + "declare " + decl + "; " + full); |
+} |
+ |
+function CheckInvalidAmbientInInnerScope(decl, full=null, preamble) { |
+ preamble = typeof(preamble) === "undefined" ? '' : preamble + '; '; |
+ CheckInvalid(preamble + "{ declare " + decl + "}"); |
+ CheckInvalid(preamble + "try { declare " + decl + "} catch (x) {}"); |
+ CheckInvalid(preamble + "function f() { declare " + decl + "}"); |
+ CheckInvalid(preamble + "for (declare " + decl + " of []) {} }"); |
+} |
+ |
+ |
+function CheckAmbientVariableDeclarations(valid, invalid=valid) { |
+ for (var key of ["var", "let", "const"]) { |
+ if (key != "const") { |
+ valid(key + " x"); |
+ valid(key + " x: number"); |
+ valid(key + " x, y"); |
+ valid(key + " x: number, y: string"); |
+ } else { |
+ valid(key + " x", key + " x = 42"); |
+ valid(key + " x: number", key + " x: number = 42"); |
+ valid(key + " x, y", key + " x = 42, y = 'hello'"); |
+ valid(key + " x: number, y: string", |
+ key + " x: number = 42, y: string = 'hello'"); |
+ } |
+ valid(key + " [x, y]", key + " [x, y] = [42, 'hello']"); |
+ valid(key + " [x, y] : [number, string]", |
+ key + " [x, y] : [number, string] = [42, 'hello']"); |
+ valid(key + " {a: x, b: y}", |
+ key + " {a: x, b: y} = {a: 42, b: 'hello'}"); |
+ valid(key + " {a: x, b: y} : {a: number, b: string}", |
+ key + " {a: x, b: y} : {a: number, b: string} = {a: 42, b: 'hello'}"); |
+ // Simple invalid declarations. |
+ invalid(key + " x : ()"); |
+ // Initializers are not allowed in ambient variable declarations. |
+ invalid(key + " x = 42"); |
+ invalid(key + " x: number = 42"); |
+ invalid(key + " x = 42, y = 'hello'"); |
+ invalid(key + " x: number = 42, y: string = 'hello'"); |
+ } |
+} |
+ |
+(function TestAmbientVariableDeclarations() { |
+ CheckAmbientVariableDeclarations(CheckValidAmbient, CheckInvalidAmbient); |
+ CheckAmbientVariableDeclarations(CheckInvalidAmbientInInnerScope); |
+})(); |
+ |
+ |
+function CheckAmbientFunctionDeclarations(valid, invalid=valid) { |
+ function check(decl) { |
+ valid(decl, decl + "{}"); |
+ invalid(decl + "{}"); // Disallow bodies in ambient function declarations. |
+ } |
+ check("function f()"); |
+ check("function f() : number"); |
+ check("function f(x: number)"); |
+ check("function f(x: number) : number"); |
+ check("function f<A>()"); |
+ check("function f<A>() : A"); |
+ check("function f<A>(x: A)"); |
+ check("function f<A, B>(x: A) : B"); |
+ // We allow generators as well. |
+ check("function* f()"); |
+ check("function* f() : number"); |
+ check("function* f(x: number)"); |
+ check("function* f(x: number) : number"); |
+ check("function* f<A>()"); |
+ check("function* f<A>() : A"); |
+ check("function* f<A>(x: A)"); |
+ check("function* f<A, B>(x: A) : B"); |
+ // Simple invalid declarations. |
+ invalid("function f() : ()"); |
+ invalid("function f(x? = 42) : ()"); |
+ invalid("function f<>()"); |
+ // The function's name must be present. |
+ invalid("function ()"); |
+ invalid("function () : number"); |
+ invalid("function (x: number)"); |
+ invalid("function (x: number) : number"); |
+ invalid("function <A>()"); |
+ invalid("function <A>() : A"); |
+ invalid("function <A>(x: A)"); |
+ invalid("function <A, B>(x: A) : B"); |
+} |
+ |
+(function TestAmbientFunctionDeclarations() { |
+ CheckAmbientFunctionDeclarations(CheckValidAmbient, CheckInvalidAmbient); |
+ CheckAmbientFunctionDeclarations(CheckInvalidAmbientInInnerScope); |
+})(); |
+ |
+ |
+function CheckAmbientClassDeclarations(valid, invalid=valid) { |
+ function check(check_header) { |
+ check_header("class C"); |
+ check_header("class C extends B", "class B {}"); |
+ check_header("class C implements I"); |
+ check_header("class C implements I, J"); |
+ check_header("class C extends B implements I", "class B {}"); |
+ check_header("class C extends B implements I, J", "class B {}"); |
+ check_header("class C<A, B>"); |
+ check_header("class C<A, B> extends D", "class D {}"); |
+ check_header("class C<A, B> implements I<A, B>"); |
+ check_header("class C<A, B> extends D implements I<A, B>", "class D {}"); |
+ } |
+ function good(members) { |
+ var ambient_body = ""; |
+ var body = ""; |
+ members.forEach(function([member, suffix='']) { |
+ if (suffix != "") suffix = " " + suffix; |
+ ambient_body += member + "; "; |
+ body += member + suffix + "; "; |
+ }); |
+ check(function (header, preamble) { |
+ valid(header + " {" + ambient_body + "}", |
+ header + " {" + body + "}", preamble); |
+ }); |
+ } |
+ function bad(member, suffix='') { |
+ check(function (header, preamble) { |
+ invalid(header + " {" + member + "}", null, preamble); |
+ if (suffix != "") { |
+ invalid(header + " {" + member + " " + suffix + "}", null, preamble); |
+ } |
+ }); |
+ } |
+ // Test all possible valid members. |
+ good([ |
+ // constructor |
+ ["constructor (x: number, y: boolean)", "{ this.x = x; this.y = y; }"], |
+ // variable members |
+ ["x"], |
+ ["y: boolean"], |
+ ["'one': number"], |
+ ["'2': boolean"], |
+ ["3: string"], |
+ // methods |
+ ["f1 () : number", "{ return 42; }"], |
+ ["f2 (a: number[]) : number", "{ return a[0]; }"], |
+ ["f3 (a: number[], b: number) : number", "{ return b || a[0]; }"], |
+ ["f4 <A, B>(a: A, b: B) : [A, B]", "{ return [a, b]; }"], |
+ // index members |
+ ["[x: string]"], |
+ ["[x: string] : number"], |
+ ["[x: number]"], |
+ ["[x: number] : boolean"] |
+ ]); |
+ // Test all possible valid static members. |
+ good([ |
+ // variable members |
+ ["static x"], |
+ ["static y: boolean"], |
+ ["static 'one': number"], |
+ ["static '2': boolean"], |
+ ["static 3: string"], |
+ // methods |
+ ["static f1 () : number", "{ return 42; }"], |
+ ["static f2 (a: number[]) : number", "{ return a[0]; }"], |
+ ["static f3 (a: number[], b: number) : number", "{ return b || a[0]; }"], |
+ ["static f4 <A, B>(a: A, b: B) : [A, B]", "{ return [a, b]; }"] |
+ ]); |
+ // Invalid constructors. |
+ bad("constructor (a : number) : boolean", "{}"), |
+ bad("constructor <A>(a : A)", "{}"); |
+ // Initializers in variable members are not allowed. |
+ bad("x = 42"), |
+ bad("x : number = 42"), |
+ bad("'four': number = 4"), |
+ bad("'5': boolean = false"), |
+ bad("6: string[] = [...['six', 'six', 'and', 'six']]"), |
+ // Getters and setters are not allowed, whether valid... |
+ bad("get x ()", "{ return 42; }"); |
+ bad("get x () : number", "{ return 42; }"); |
+ bad("set x (a)", "{}"); |
+ bad("set x (a) : void", "{}"); |
+ bad("set x (a : number)", "{}"); |
+ bad("set x (a : number) : void", "{}"); |
+ // ... or invalid. |
+ bad("get x (a)", "{ return 42; }"); |
+ bad("get x (a) : number", "{ return 42; }"); |
+ bad("get x (a, b)", "{ return 42; }"); |
+ bad("get x (a, b) : number", "{ return 42; }"); |
+ bad("get x (a : number)", "{ return 42; }"); |
+ bad("get x (a : number) : number", "{ return 42; }"); |
+ bad("get x <A>()", "{ return 42; }"); |
+ bad("set x ()", "{}"); |
+ bad("set x () : void", "{}"); |
+ bad("set x (a : number, b : number)", "{}"); |
+ bad("set x (a : number, b : number) : void", "{}"); |
+ bad("set x (...rest)", "{}"); |
+ bad("set x (...rest : string[]) : void", "{}"); |
+ bad("set x <A>(a : A)", "{}"); |
+} |
+ |
+(function TestAmbientClassDeclarations() { |
+ CheckAmbientClassDeclarations(CheckValidAmbient, CheckInvalidAmbient); |
+ CheckAmbientClassDeclarations(CheckInvalidAmbientInInnerScope); |
+})(); |
+ |
+(function TestMoreInvalidAmbients() { |
+ CheckInvalidAmbient("type N = number"); |
+ CheckInvalidAmbient("interface I {}"); |
+ CheckInvalidAmbient("x = 42"); |
+ CheckInvalidAmbient("{}"); |
+ CheckInvalidAmbient("while (true) {}"); |
+})(); |