Commit bcb1b873 authored by ishell's avatar ishell Committed by Commit bot

[es8] Throw SyntaxError when tail call expressions occur in non-strict mode.

BUG=v8:4915
LOG=N

Review-Url: https://codereview.chromium.org/1955393002
Cr-Commit-Position: refs/heads/master@{#36105}
parent 4cad4c05
...@@ -446,6 +446,8 @@ class CallSite { ...@@ -446,6 +446,8 @@ class CallSite {
T(UnexpectedReserved, "Unexpected reserved word") \ T(UnexpectedReserved, "Unexpected reserved word") \
T(UnexpectedStrictReserved, "Unexpected strict mode reserved word") \ T(UnexpectedStrictReserved, "Unexpected strict mode reserved word") \
T(UnexpectedSuper, "'super' keyword unexpected here") \ T(UnexpectedSuper, "'super' keyword unexpected here") \
T(UnexpectedSloppyTailCall, \
"Tail call expressions are not allowed in non-strict mode") \
T(UnexpectedNewTarget, "new.target expression is not allowed here") \ T(UnexpectedNewTarget, "new.target expression is not allowed here") \
T(UnexpectedTailCall, "Tail call expression is not allowed here") \ T(UnexpectedTailCall, "Tail call expression is not allowed here") \
T(UnexpectedTailCallInCatchBlock, \ T(UnexpectedTailCallInCatchBlock, \
......
...@@ -2228,6 +2228,17 @@ ParserBase<Traits>::ParseTailCallExpression(ExpressionClassifier* classifier, ...@@ -2228,6 +2228,17 @@ ParserBase<Traits>::ParseTailCallExpression(ExpressionClassifier* classifier,
CheckNoTailCallExpressions(classifier, CHECK_OK); CheckNoTailCallExpressions(classifier, CHECK_OK);
Scanner::Location loc(pos, scanner()->location().end_pos); Scanner::Location loc(pos, scanner()->location().end_pos);
if (!expression->IsCall()) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedInsideTailCall);
*ok = false;
return Traits::EmptyExpression();
}
if (!is_strict(language_mode())) {
ReportMessageAt(loc, MessageTemplate::kUnexpectedSloppyTailCall);
*ok = false;
return Traits::EmptyExpression();
}
ReturnExprContext return_expr_context = ReturnExprContext return_expr_context =
function_state_->return_expr_context(); function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) { if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
...@@ -2250,12 +2261,6 @@ ParserBase<Traits>::ParseTailCallExpression(ExpressionClassifier* classifier, ...@@ -2250,12 +2261,6 @@ ParserBase<Traits>::ParseTailCallExpression(ExpressionClassifier* classifier,
*ok = false; *ok = false;
return Traits::EmptyExpression(); return Traits::EmptyExpression();
} }
if (!expression->IsCall()) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedInsideTailCall);
*ok = false;
return Traits::EmptyExpression();
}
classifier->RecordTailCallExpressionError( classifier->RecordTailCallExpressionError(
loc, MessageTemplate::kUnexpectedTailCall); loc, MessageTemplate::kUnexpectedTailCall);
function_state_->AddExpressionInTailPosition(expression, loc); function_state_->AddExpressionInTailPosition(expression, loc);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f() - a ; return continue f() - a ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return b + continue f() ; return b + continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return 1, 2, 3, continue f() , 4 ; return 1, 2, 3, continue f() , 4 ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function g() { function g() {
return class A extends continue f() {}; return class A extends continue f() {};
......
*%(basename)s:8: SyntaxError: Tail call expression is not allowed here *%(basename)s:9: SyntaxError: Tail call expression is not allowed here
return class A extends continue f() {}; return class A extends continue f() {};
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body *%(basename)s:14: SyntaxError: Tail call expression in for-in/of body
return continue f() ; return continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression in for-in/of body SyntaxError: Tail call expression in for-in/of body
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:13: SyntaxError: Tail call expression in for-in/of body *%(basename)s:14: SyntaxError: Tail call expression in for-in/of body
return continue f() ; return continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression in for-in/of body SyntaxError: Tail call expression in for-in/of body
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f() && a ; return continue f() && a ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f() || a ; return continue f() || a ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function g() { function g() {
class A {}; class A {};
......
*%(basename)s:11: SyntaxError: Tail call expression is not allowed here *%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return continue f() ; return continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:15: SyntaxError: Tail call expression in catch block when finally block is also present *%(basename)s:16: SyntaxError: Tail call expression in catch block when finally block is also present
return continue f() ; return continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression in catch block when finally block is also present SyntaxError: Tail call expression in catch block when finally block is also present
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:16: SyntaxError: Tail call expression in try block *%(basename)s:17: SyntaxError: Tail call expression in try block
return continue f() ; return continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression in try block SyntaxError: Tail call expression in try block
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:13: SyntaxError: Tail call expression in try block *%(basename)s:14: SyntaxError: Tail call expression in try block
return continue f() ; return continue f() ;
^^^^^^^^^^^^ ^^^^^^^^^^^^
SyntaxError: Tail call expression in try block SyntaxError: Tail call expression in try block
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return (continue f(1)) (2) ; return (continue f(1)) (2) ;
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function g(x) { function g(x) {
return continue x ; return continue x ;
......
*%(basename)s:8: SyntaxError: Unexpected expression inside tail call *%(basename)s:9: SyntaxError: Unexpected expression inside tail call
return continue x ; return continue x ;
^ ^
SyntaxError: Unexpected expression inside tail call SyntaxError: Unexpected expression inside tail call
// 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-explicit-tailcalls
function g() {
return continue f() ;
}
*%(basename)s:8: SyntaxError: Tail call expressions are not allowed in non-strict mode
return continue f() ;
^^^^^^^^^^^^^
SyntaxError: Tail call expressions are not allowed in non-strict mode
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
// Flags: --harmony-explicit-tailcalls // Flags: --harmony-explicit-tailcalls
"use strict";
function f() { function f() {
return 1; return 1;
......
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here *%(basename)s:13: SyntaxError: Tail call expression is not allowed here
var x = continue f() ; var x = continue f() ;
^^^^^^^^^^^^^ ^^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here SyntaxError: Tail call expression is not allowed here
...@@ -261,9 +261,8 @@ function f_153(expected_call_stack, a) { ...@@ -261,9 +261,8 @@ function f_153(expected_call_stack, a) {
} }
%NeverOptimizeFunction(g); %NeverOptimizeFunction(g);
var context = 10;
function f(v) { function f(v) {
return g(context); return g();
} }
%SetForceInlineFlag(f); %SetForceInlineFlag(f);
......
// 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: --allow-natives-syntax --harmony-explicit-tailcalls
// Flags: --harmony-do-expressions
var SyntaxErrorTests = [
{ msg: "Unexpected expression inside tail call",
tests: [
{ src: `()=>{ return continue foo ; }`,
err: ` ^^^`,
},
{ src: `()=>{ return continue 42 ; }`,
err: ` ^^`,
},
{ src: `()=>{ return continue new foo () ; }`,
err: ` ^^^^^^^^^^`,
},
{ src: `()=>{ loop: return continue loop ; }`,
err: ` ^^^^`,
},
{ src: `class A { foo() { return continue super.x ; } }`,
err: ` ^^^^^^^`,
},
{ src: `()=>{ return continue this ; }`,
err: ` ^^^^`,
},
{ src: `()=>{ return continue class A {} ; }`,
err: ` ^^^^^^^^^^`,
},
{ src: `()=>{ return continue class A extends B {} ; }`,
err: ` ^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue function A() { } ; }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue { a: b, c: d} ; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue function* Gen() { yield 1; } ; }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `function A() { return continue new.target ; }`,
err: ` ^^^^^^^^^^`,
},
{ src: `()=>{ return continue () ; }`,
err: ` ^^`,
},
{ src: `()=>{ return continue ( 42 ) ; }`,
err: ` ^^^^^^`,
},
{ src: "()=>{ return continue `123 ${foo} 34lk` ; }",
err: ` ^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue do { x ? foo() : bar() ; } }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
],
},
{ msg: "Tail call expression is not allowed here",
tests: [
{ src: `class A {}; class B extends A { constructor() { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^`,
},
{ src: `class A extends continue f () {}; }`,
err: ` ^^^^^^^^^^^^^`,
},
],
},
{ msg: "Tail call expressions are not allowed in non-strict mode",
tests: [
{ src: `()=>{ return continue continue continue b() ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue ( continue b() ) ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue f() - a ; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `()=>{ return b + continue f() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return 1, 2, 3, continue f() , 4 ; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `()=>{ var x = continue f ( ) ; }`,
err: ` ^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue f () ? 1 : 2 ; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `()=>{ return (1, 2, 3, continue f()), 4; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return [1, 2, continue f() ] ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return [1, 2, ... continue f() ] ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return [1, 2, continue f(), 3 ] ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: "()=>{ return `123 ${a} ${ continue foo ( ) } 34lk` ; }",
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return g( 1, 2, continue f() ); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue f() || a; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a || b || c || continue f() || d; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a && b && c && continue f() && d; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a && b || c && continue f() ? d : e; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a ? b : c && continue f() && d || e; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue foo() instanceof bar ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return bar instanceof continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue foo() in bar ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return bar in continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ function* G() { yield continue foo(); } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ (1, 2, 3, continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a <= continue f(); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return b > continue f(); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a << continue f(); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return b >> continue f(); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return c >>> continue f(); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue f() = a ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a = continue f() ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a += continue f(); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a ** continue f() ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return delete continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ typeof continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return ~ continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return void continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return !continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return -continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return +continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return ++ continue f( ) ; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue f() ++; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue f() --; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return (continue foo()) () ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ for (var i = continue foo(); i < 10; i++) bar(); }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ for (var i = 0; i < continue foo(); i++) bar(); }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ for (var i = 0; i < 10; continue foo()) bar(); }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ if (continue foo()) bar(); }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ while (continue foo()) bar(); }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ do { smth; } while (continue foo()) ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ throw continue foo() ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ switch (continue foo()) { case 1: break; } ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ with (continue foo()) { smth; } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ let x = continue foo() }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ const c = continue foo() }`,
err: ` ^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ try { return continue f ( ) ; } catch(e) {} }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ try { try { smth; } catch(e) { return continue f( ) ; } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ try { try { smth; } catch(e) { return continue f( ) ; } } finally { bla; } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ try { smth; } catch(e) { return continue f ( ) ; } finally { blah; } }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ try { smth; } catch(e) { try { smth; } catch (e) { return continue f ( ) ; } } finally { blah; } }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ for (var v in {a:0}) { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ for (var v of [1, 2, 3]) { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue a.b.c.foo () ; }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue a().b.c().d.foo () ; }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue foo (1)(2)(3, 4) ; }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return ( continue b() ) ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: "()=>{ return continue bar`ab cd ef` ; }",
err: ` ^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: "()=>{ return continue bar`ab ${cd} ef` ; }",
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return a || continue f() ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a && continue f() ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a , continue f() ; }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ function* G() { return continue foo(); } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ function B() { return continue new.target() ; } }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue do { x ? foo() : bar() ; }() }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return continue (do { x ? foo() : bar() ; })() }`,
err: ` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return do { 1, continue foo() } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return do { x ? continue foo() : y } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return a || (b && continue c()); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a && (b || continue c()); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return a || (b ? c : continue d()); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=>{ return 1, 2, 3, a || (b ? c : continue d()); }`,
err: ` ^^^^^^^^^^^^`,
},
{ src: `()=> continue (foo ()) ;`,
err: ` ^^^^^^^^^^^^^^^^^^`,
},
{ src: `()=> a || continue foo () ;`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=> a && continue foo () ;`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=> a ? continue foo () : b;`,
err: ` ^^^^^^^^^^^^^^^^`,
},
],
},
{ msg: "Undefined label 'foo'",
tests: [
{ src: `()=>{ continue foo () ; }`,
err: ` ^^^`,
},
],
},
];
// Should parse successfully.
var NoErrorTests = [
`()=>{ class A { foo() { return continue super.f() ; } } }`,
`()=>{ class A { foo() { return continue f() ; } } }`,
`()=>{ class A { foo() { return a || continue f() ; } } }`,
`()=>{ class A { foo() { return b && continue f() ; } } }`,
];
(function() {
for (var test_set of SyntaxErrorTests) {
var expected_message = "SyntaxError: " + test_set.msg;
for (var test of test_set.tests) {
var passed = true;
var e = null;
try {
Realm.eval(0, test.src);
} catch (ee) {
e = ee;
}
print("=======================================");
print("Expected | " + expected_message);
print("Source | " + test.src);
print(" | " + test.err);
if (e === null) {
print("FAILED");
throw new Error("SyntaxError was not thrown");
}
var details = %GetExceptionDetails(e);
if (details.start_pos == undefined ||
details.end_pos == undefined) {
throw new Error("Bad message object returned");
}
var underline = " ".repeat(details.start_pos) +
"^".repeat(details.end_pos - details.start_pos);
var passed = expected_message === e.toString() &&
test.err === underline;
if (passed) {
print("PASSED");
print();
} else {
print("---------------------------------------");
print("Actual | " + e);
print("Source | " + test.src);
print(" | " + underline);
print("FAILED");
throw new Error("Test failed");
}
}
}
})();
(function() {
for (var src of NoErrorTests) {
print("=======================================");
print("Source | " + src);
Realm.eval(0, src);
print("PASSED");
print();
}
})();
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
// Flags: --allow-natives-syntax --harmony-explicit-tailcalls // Flags: --allow-natives-syntax --harmony-explicit-tailcalls
// Flags: --harmony-do-expressions // Flags: --harmony-do-expressions
"use strict";
var SyntaxErrorTests = [ var SyntaxErrorTests = [
{ msg: "Unexpected expression inside tail call", { msg: "Unexpected expression inside tail call",
...@@ -222,17 +223,14 @@ var SyntaxErrorTests = [ ...@@ -222,17 +223,14 @@ var SyntaxErrorTests = [
{ src: `()=>{ switch (continue foo()) { case 1: break; } ; }`, { src: `()=>{ switch (continue foo()) { case 1: break; } ; }`,
err: ` ^^^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^^^`,
}, },
{ src: `()=>{ with (continue foo()) { smth; } }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ let x = continue foo() }`, { src: `()=>{ let x = continue foo() }`,
err: ` ^^^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^^^`,
}, },
{ src: `()=>{ const c = continue foo() }`, { src: `()=>{ const c = continue foo() }`,
err: ` ^^^^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^^^^`,
}, },
{ src: `class A {}; class B extends A { constructor() { return continue super () ; } }`, { src: `class A {}; class B extends A { constructor() { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^^^^`,
}, },
{ src: `class A extends continue f () {}; }`, { src: `class A extends continue f () {}; }`,
err: ` ^^^^^^^^^^^^^`, err: ` ^^^^^^^^^^^^^`,
...@@ -312,13 +310,13 @@ var NoErrorTests = [ ...@@ -312,13 +310,13 @@ var NoErrorTests = [
(function() { (function() {
for (test_set of SyntaxErrorTests) { for (var test_set of SyntaxErrorTests) {
var expected_message = "SyntaxError: " + test_set.msg; var expected_message = "SyntaxError: " + test_set.msg;
for (test of test_set.tests) { for (var test of test_set.tests) {
var passed = true; var passed = true;
var e = null; var e = null;
try { try {
Realm.eval(0, test.src); eval(test.src);
} catch (ee) { } catch (ee) {
e = ee; e = ee;
} }
...@@ -359,9 +357,10 @@ var NoErrorTests = [ ...@@ -359,9 +357,10 @@ var NoErrorTests = [
(function() { (function() {
for (src of NoErrorTests) { for (var src of NoErrorTests) {
print("======================================="); print("=======================================");
print("Source | " + src); print("Source | " + src);
src = `"use strict"; ` + src;
Realm.eval(0, src); Realm.eval(0, src);
print("PASSED"); print("PASSED");
print(); print();
......
...@@ -4,10 +4,27 @@ ...@@ -4,10 +4,27 @@
// Flags: --allow-natives-syntax --harmony-explicit-tailcalls --stack-size=100 // Flags: --allow-natives-syntax --harmony-explicit-tailcalls --stack-size=100
//
// Tail calls work only in strict mode.
//
(function() {
function f(n) {
if (n <= 0) {
return "foo";
}
return f(n - 1);
}
assertThrows(()=>{ f(1e5) });
%OptimizeFunctionOnNextCall(f);
assertThrows(()=>{ f(1e5) });
})();
// //
// Tail call normal functions. // Tail call normal functions.
// //
(function() { (function() {
"use strict";
function f(n) { function f(n) {
if (n <= 0) { if (n <= 0) {
return "foo"; return "foo";
...@@ -21,6 +38,7 @@ ...@@ -21,6 +38,7 @@
(function() { (function() {
"use strict";
function f(n) { function f(n) {
if (n <= 0) { if (n <= 0) {
return "foo"; return "foo";
...@@ -34,6 +52,7 @@ ...@@ -34,6 +52,7 @@
(function() { (function() {
"use strict";
function f(n){ function f(n){
if (n <= 0) { if (n <= 0) {
return "foo"; return "foo";
...@@ -55,6 +74,7 @@ ...@@ -55,6 +74,7 @@
(function() { (function() {
"use strict";
function f(n){ function f(n){
if (n <= 0) { if (n <= 0) {
return "foo"; return "foo";
...@@ -79,6 +99,7 @@ ...@@ -79,6 +99,7 @@
// Tail call bound functions. // Tail call bound functions.
// //
(function() { (function() {
"use strict";
function f0(n) { function f0(n) {
if (n <= 0) { if (n <= 0) {
return "foo"; return "foo";
...@@ -96,6 +117,7 @@ ...@@ -96,6 +117,7 @@
(function() { (function() {
"use strict";
function f0(n){ function f0(n){
if (n <= 0) { if (n <= 0) {
return "foo"; return "foo";
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
// Flags: --allow-natives-syntax --harmony-explicit-tailcalls // Flags: --allow-natives-syntax --harmony-explicit-tailcalls
// Flags: --harmony-do-expressions // Flags: --harmony-do-expressions
"use strict";
Error.prepareStackTrace = (error,stack) => { Error.prepareStackTrace = (error,stack) => {
error.strace = stack; error.strace = stack;
return error.message + "\n at " + stack.join("\n at "); return error.message + "\n at " + stack.join("\n at ");
...@@ -20,6 +22,8 @@ function CheckStackTrace(expected) { ...@@ -20,6 +22,8 @@ function CheckStackTrace(expected) {
assertEquals(expected[i].name, stack[i + 1].getFunctionName()); assertEquals(expected[i].name, stack[i + 1].getFunctionName());
} }
} }
%NeverOptimizeFunction(CheckStackTrace);
function f(expected_call_stack, a, b) { function f(expected_call_stack, a, b) {
CheckStackTrace(expected_call_stack); CheckStackTrace(expected_call_stack);
...@@ -221,6 +225,87 @@ function f_153(expected_call_stack, a) { ...@@ -221,6 +225,87 @@ function f_153(expected_call_stack, a) {
})(); })();
// Tail calling from getter.
(function() {
function g(v) {
CheckStackTrace([g, test]);
%DeoptimizeFunction(test);
return 153;
}
%NeverOptimizeFunction(g);
function f(v) {
return continue g();
}
%SetForceInlineFlag(f);
function test() {
var o = {};
o.__defineGetter__('p', f);
assertEquals(153, o.p);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling from setter.
(function() {
function g() {
CheckStackTrace([g, test]);
%DeoptimizeFunction(test);
return 153;
}
%NeverOptimizeFunction(g);
function f(v) {
return continue g();
}
%SetForceInlineFlag(f);
function test() {
var o = {};
o.__defineSetter__('q', f);
assertEquals(1, o.q = 1);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling from constructor.
(function() {
function g(context) {
CheckStackTrace([g, test]);
%DeoptimizeFunction(test);
return {x: 153};
}
%NeverOptimizeFunction(g);
function A() {
this.x = 42;
return continue g();
}
function test() {
var o = new A();
%DebugPrint(o);
assertEquals(153, o.x);
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail calling via various expressions. // Tail calling via various expressions.
(function() { (function() {
function g1(a) { function g1(a) {
...@@ -294,6 +379,38 @@ function f_153(expected_call_stack, a) { ...@@ -294,6 +379,38 @@ function f_153(expected_call_stack, a) {
})(); })();
// Tail calling from various statements.
(function() {
function g3() {
for (var i = 0; i < 10; i++) {
return continue f_153([f_153, test]);
}
}
function g4() {
while (true) {
return continue f_153([f_153, test]);
}
}
function g5() {
do {
return continue f_153([f_153, test]);
} while (true);
}
function test() {
assertEquals(153, g3());
assertEquals(153, g4());
assertEquals(153, g5());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from try-catch constructs. // Test tail calls from try-catch constructs.
(function() { (function() {
function tc1(a) { function tc1(a) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment