Commit 632e261a authored by ishell's avatar ishell Committed by Commit bot

[es8] Remove syntactic tail calls support.

BUG=v8:4915

Review-Url: https://codereview.chromium.org/2372513003
Cr-Commit-Position: refs/heads/master@{#39808}
parent 24e29f28
......@@ -2845,7 +2845,6 @@ EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_lookbehind)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_named_captures)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_regexp_property)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_function_sent)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_explicit_tailcalls)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_tailcalls)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_restrictive_declarations)
EMPTY_INITIALIZE_GLOBAL_FOR_FEATURE(harmony_string_padding)
......@@ -3428,7 +3427,6 @@ bool Genesis::InstallNatives(GlobalContextType context_type) {
bool Genesis::InstallExperimentalNatives() {
static const char* harmony_explicit_tailcalls_natives[] = {nullptr};
static const char* harmony_tailcalls_natives[] = {nullptr};
static const char* harmony_sharedarraybuffer_natives[] = {
"native harmony-atomics.js", NULL};
......
......@@ -198,7 +198,6 @@ DEFINE_IMPLICATION(es_staging, move_object_start)
V(harmony_function_sent, "harmony function.sent") \
V(harmony_sharedarraybuffer, "harmony sharedarraybuffer") \
V(harmony_simd, "harmony simd") \
V(harmony_explicit_tailcalls, "harmony explicit tail calls") \
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_restrictive_generators, \
"harmony restrictions on generator declarations") \
......
......@@ -593,19 +593,10 @@ class ErrorUtils : public AllStatic {
T(UnexpectedEOS, "Unexpected end of input") \
T(UnexpectedFunctionSent, \
"function.sent expression is not allowed outside a generator") \
T(UnexpectedInsideTailCall, "Unexpected expression inside tail call") \
T(UnexpectedReserved, "Unexpected reserved word") \
T(UnexpectedStrictReserved, "Unexpected strict mode reserved word") \
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(UnexpectedTailCall, "Tail call expression is not allowed here") \
T(UnexpectedTailCallInCatchBlock, \
"Tail call expression in catch block when finally block is also present") \
T(UnexpectedTailCallInForInOf, "Tail call expression in for-in/of body") \
T(UnexpectedTailCallInTryBlock, "Tail call expression in try block") \
T(UnexpectedTailCallOfEval, "Tail call of a direct eval is not allowed") \
T(UnexpectedTemplateString, "Unexpected template string") \
T(UnexpectedToken, "Unexpected token %") \
T(UnexpectedTokenIdentifier, "Unexpected identifier") \
......
......@@ -344,14 +344,6 @@ class ParserBase {
expressions_.Add(expr, zone_);
}
void AddExplicitTailCall(ExpressionT expr, const Scanner::Location& loc) {
if (!has_explicit_tail_calls()) {
loc_ = loc;
has_explicit_tail_calls_ = true;
}
expressions_.Add(expr, zone_);
}
void Append(const TailCallExpressionList& other) {
if (!has_explicit_tail_calls()) {
loc_ = other.loc_;
......@@ -445,14 +437,6 @@ class ParserBase {
tail_call_expressions_.AddImplicitTailCall(expression);
}
}
void AddExplicitTailCallExpression(ExpressionT expression,
const Scanner::Location& loc) {
DCHECK(expression->IsCall());
if (return_expr_context() ==
ReturnExprContext::kInsideValidReturnStatement) {
tail_call_expressions_.AddExplicitTailCall(expression, loc);
}
}
ZoneList<typename ExpressionClassifier::Error>* GetReportedErrorList() {
return &reported_errors_;
......@@ -1064,14 +1048,6 @@ class ParserBase {
}
}
void CheckNoTailCallExpressions(bool* ok) {
if (FLAG_harmony_explicit_tailcalls &&
classifier()->has_tail_call_expression()) {
ReportClassifierError(classifier()->tail_call_expression_error());
*ok = false;
}
}
void ExpressionUnexpectedToken() {
MessageTemplate::Template message = MessageTemplate::kUnexpectedToken;
const char* arg;
......@@ -1182,7 +1158,6 @@ class ParserBase {
ExpressionT ParseAssignmentExpression(bool accept_IN, bool* ok);
ExpressionT ParseYieldExpression(bool accept_IN, bool* ok);
ExpressionT ParseTailCallExpression(bool* ok);
ExpressionT ParseConditionalExpression(bool accept_IN, bool* ok);
ExpressionT ParseBinaryExpression(int prec, bool accept_IN, bool* ok);
ExpressionT ParseUnaryExpression(bool* ok);
......@@ -1868,7 +1843,6 @@ ParserBase<Impl>::ParseExpressionCoverGrammar(bool accept_IN, bool* ok) {
ExpressionT result = impl()->EmptyExpression();
while (true) {
CheckNoTailCallExpressions(CHECK_OK);
int comma_pos = position();
ExpressionClassifier binding_classifier(this);
ExpressionT right;
......@@ -1937,7 +1911,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
Consume(Token::ELLIPSIS);
int expr_pos = peek_position();
ExpressionT argument = ParseAssignmentExpression(true, CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
elem = factory()->NewSpread(argument, start_pos, expr_pos);
if (first_spread_index < 0) {
......@@ -1961,7 +1934,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseArrayLiteral(
} else {
int beg_pos = peek_position();
elem = ParseAssignmentExpression(true, CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
CheckDestructuringElement(elem, beg_pos, scanner()->location().end_pos);
}
values->Add(elem, zone_);
......@@ -2545,7 +2517,6 @@ typename ParserBase<Impl>::ExpressionListT ParserBase<Impl>::ParseArguments(
ExpressionT argument =
ParseAssignmentExpression(true, CHECK_OK_CUSTOM(NullExpressionList));
CheckNoTailCallExpressions(CHECK_OK_CUSTOM(NullExpressionList));
if (!maybe_arrow) {
impl()->RewriteNonPattern(CHECK_OK_CUSTOM(NullExpressionList));
}
......@@ -2739,8 +2710,6 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
impl()->Accumulate(productions, false);
}
CheckNoTailCallExpressions(CHECK_OK);
if (is_destructuring_assignment) {
ValidateAssignmentPattern(CHECK_OK);
} else {
......@@ -2762,7 +2731,6 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN, bool* ok) {
ExpressionClassifier rhs_classifier(this);
ExpressionT right = ParseAssignmentExpression(accept_IN, CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
......@@ -2859,75 +2827,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseYieldExpression(
return yield;
}
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
ParserBase<Impl>::ParseTailCallExpression(bool* ok) {
// TailCallExpression::
// 'continue' MemberExpression Arguments
// 'continue' CallExpression Arguments
// 'continue' MemberExpression TemplateLiteral
// 'continue' CallExpression TemplateLiteral
Expect(Token::CONTINUE, CHECK_OK);
int pos = position();
int sub_expression_pos = peek_position();
ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
Scanner::Location loc(pos, scanner()->location().end_pos);
if (!expression->IsCall()) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
impl()->ReportMessageAt(sub_loc,
MessageTemplate::kUnexpectedInsideTailCall);
*ok = false;
return impl()->EmptyExpression();
}
if (impl()->IsDirectEvalCall(expression)) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
impl()->ReportMessageAt(sub_loc,
MessageTemplate::kUnexpectedTailCallOfEval);
*ok = false;
return impl()->EmptyExpression();
}
if (!is_strict(language_mode())) {
impl()->ReportMessageAt(loc, MessageTemplate::kUnexpectedSloppyTailCall);
*ok = false;
return impl()->EmptyExpression();
}
if (is_resumable()) {
Scanner::Location sub_loc(sub_expression_pos, loc.end_pos);
impl()->ReportMessageAt(sub_loc, MessageTemplate::kUnexpectedTailCall);
*ok = false;
return impl()->EmptyExpression();
}
ReturnExprContext return_expr_context =
function_state_->return_expr_context();
if (return_expr_context != ReturnExprContext::kInsideValidReturnStatement) {
MessageTemplate::Template msg = MessageTemplate::kNone;
switch (return_expr_context) {
case ReturnExprContext::kInsideValidReturnStatement:
UNREACHABLE();
return impl()->EmptyExpression();
case ReturnExprContext::kInsideValidBlock:
msg = MessageTemplate::kUnexpectedTailCall;
break;
case ReturnExprContext::kInsideTryBlock:
msg = MessageTemplate::kUnexpectedTailCallInTryBlock;
break;
case ReturnExprContext::kInsideForInOfBody:
msg = MessageTemplate::kUnexpectedTailCallInForInOf;
break;
}
impl()->ReportMessageAt(loc, msg);
*ok = false;
return impl()->EmptyExpression();
}
classifier()->RecordTailCallExpressionError(
loc, MessageTemplate::kUnexpectedTailCall);
function_state_->AddExplicitTailCallExpression(expression, loc);
return expression;
}
// Precedence = 3
template <typename Impl>
typename ParserBase<Impl>::ExpressionT
......@@ -2941,7 +2840,6 @@ ParserBase<Impl>::ParseConditionalExpression(bool accept_IN,
// We start using the binary expression parser for prec >= 4 only!
ExpressionT expression = ParseBinaryExpression(4, accept_IN, CHECK_OK);
if (peek() != Token::CONDITIONAL) return expression;
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -2967,7 +2865,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
// prec1 >= 4
while (Precedence(peek(), accept_IN) == prec1) {
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -2977,9 +2874,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseBinaryExpression(
const bool is_right_associative = op == Token::EXP;
const int next_prec = is_right_associative ? prec1 : prec1 + 1;
ExpressionT y = ParseBinaryExpression(next_prec, accept_IN, CHECK_OK);
if (op != Token::OR && op != Token::AND) {
CheckNoTailCallExpressions(CHECK_OK);
}
impl()->RewriteNonPattern(CHECK_OK);
if (impl()->ShortcutNumericLiteralBinaryExpression(&x, y, op, pos)) {
......@@ -3037,7 +2931,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
op = Next();
int pos = position();
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
if (op == Token::DELETE && is_strict(language_mode())) {
......@@ -3063,7 +2956,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseUnaryExpression(
op = Next();
int beg_pos = peek_position();
ExpressionT expression = ParseUnaryExpression(CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
expression = CheckAndRewriteReferenceExpression(
expression, beg_pos, scanner()->location().end_pos,
MessageTemplate::kInvalidLhsInPrefixOp, CHECK_OK);
......@@ -3101,7 +2993,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParsePostfixExpression(
ExpressionT expression = ParseLeftHandSideExpression(CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) {
CheckNoTailCallExpressions(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -3127,10 +3018,6 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
// LeftHandSideExpression ::
// (NewExpression | MemberExpression) ...
if (FLAG_harmony_explicit_tailcalls && peek() == Token::CONTINUE) {
return ParseTailCallExpression(ok);
}
bool is_async = false;
ExpressionT result =
ParseMemberWithNewPrefixesExpression(&is_async, CHECK_OK);
......@@ -3138,7 +3025,6 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
while (true) {
switch (peek()) {
case Token::LBRACK: {
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -3152,7 +3038,6 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
}
case Token::LPAREN: {
CheckNoTailCallExpressions(CHECK_OK);
int pos;
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
......@@ -3240,7 +3125,6 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
}
case Token::PERIOD: {
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -3255,7 +3139,6 @@ ParserBase<Impl>::ParseLeftHandSideExpression(bool* ok) {
case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: {
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
BindingPatternUnexpectedToken();
ArrowFormalParametersUnexpectedToken();
......@@ -4163,7 +4046,6 @@ typename ParserBase<Impl>::ExpressionT ParserBase<Impl>::ParseTemplateLiteral(
int expr_pos = peek_position();
ExpressionT expression = ParseExpressionCoverGrammar(true, CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
impl()->RewriteNonPattern(CHECK_OK);
impl()->AddTemplateExpression(&ts, expression);
......@@ -5082,16 +4964,6 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
DCHECK(peek() == Token::FINALLY || !impl()->IsNullStatement(catch_block));
if (Check(Token::FINALLY)) {
finally_block = ParseBlock(nullptr, CHECK_OK);
if (FLAG_harmony_explicit_tailcalls &&
catch_info.tail_call_expressions.has_explicit_tail_calls()) {
// TODO(ishell): update chapter number.
// ES8 XX.YY.ZZ
impl()->ReportMessageAt(catch_info.tail_call_expressions.location(),
MessageTemplate::kUnexpectedTailCallInCatchBlock);
*ok = false;
return impl()->NullStatement();
}
}
return impl()->RewriteTryStatement(try_block, catch_block, finally_block,
......
......@@ -3550,7 +3550,6 @@ Expression* Parser::ParseClassLiteral(const AstRawString* name,
block_state.set_start_position(scanner()->location().end_pos);
ExpressionClassifier extends_classifier(this);
extends = ParseLeftHandSideExpression(CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
RewriteNonPattern(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
} else {
......@@ -4221,12 +4220,7 @@ void Parser::MarkCollectedTailCallExpressions() {
const ZoneList<Expression*>& tail_call_expressions =
function_state_->tail_call_expressions().expressions();
for (int i = 0; i < tail_call_expressions.length(); ++i) {
Expression* expression = tail_call_expressions[i];
// If only FLAG_harmony_explicit_tailcalls is enabled then expression
// must be a Call expression.
DCHECK(FLAG_harmony_tailcalls || !FLAG_harmony_explicit_tailcalls ||
expression->IsCall());
MarkTailPosition(expression);
MarkTailPosition(tail_call_expressions[i]);
}
}
......
......@@ -278,7 +278,6 @@ PreParserExpression PreParser::ParseClassLiteral(
if (has_extends) {
ExpressionClassifier extends_classifier(this);
ParseLeftHandSideExpression(CHECK_OK);
CheckNoTailCallExpressions(CHECK_OK);
ValidateExpression(CHECK_OK);
impl()->AccumulateFormalParameterContainmentErrors();
}
......
// 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 f() {
return 1;
}
function* g() {
'use strict';
return continue f();
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f();
^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function f() {
return 1;
}
function g() {
return continue f() - a ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f() - a ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function f() {
return 1;
}
function g() {
return b + continue f() ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return b + continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function f() {
return 1;
}
function g() {
return 1, 2, 3, continue f() , 4 ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return 1, 2, 3, continue f() , 4 ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function g() {
return class A extends continue f() {};
}
*%(basename)s:9: SyntaxError: Tail call expression is not allowed here
return class A extends continue f() {};
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function f() {
return 1;
}
function g() {
for (var v in {a:0}) {
return continue f() ;
}
}
*%(basename)s:14: SyntaxError: Tail call expression in for-in/of body
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in for-in/of body
// 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
"use strict";
function f() {
return 1;
}
function g() {
for (var v of [1, 2, 3]) {
return continue f() ;
}
}
*%(basename)s:14: SyntaxError: Tail call expression in for-in/of body
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in for-in/of body
// 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
"use strict";
function f() {
return 1;
}
function g() {
return continue f() && a ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f() && a ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function f() {
return 1;
}
function g() {
return continue f() || a ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return continue f() || a ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function g() {
class A {};
class B extends A {
constructor() {
return continue f() ;
}
}
}
*%(basename)s:12: SyntaxError: Tail call expression is not allowed here
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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
"use strict";
function f() {
return 1;
}
function g() {
try {
f();
} catch(e) {
return continue f() ;
} finally {
f();
}
}
*%(basename)s:16: SyntaxError: Tail call expression in catch block when finally block is also present
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in catch block when finally block is also present
// 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
"use strict";
function f() {
return 1;
}
function g() {
try {
try {
f();
} catch(e) {
return continue f() ;
}
} finally {
f();
}
}
*%(basename)s:17: SyntaxError: Tail call expression in try block
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in try block
// 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
"use strict";
function f() {
return 1;
}
function g() {
try {
return continue f() ;
} catch(e) {
}
}
*%(basename)s:14: SyntaxError: Tail call expression in try block
return continue f() ;
^^^^^^^^^^^^
SyntaxError: Tail call expression in try block
// 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
"use strict";
function f() {
return 1;
}
function g() {
return (continue f(1)) (2) ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
return (continue f(1)) (2) ;
^^^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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 eval ("f()") ;
}
*%(basename)s:8: SyntaxError: Tail call of a direct eval is not allowed
return continue eval ("f()") ;
^^^^^^^^^^^^^
SyntaxError: Tail call of a direct eval is not allowed
// 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
"use strict";
function g(x) {
return continue x ;
}
*%(basename)s:9: SyntaxError: Unexpected expression inside tail call
return continue x ;
^
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 f() {
return 1;
}
function g() {
return continue new f() ;
}
*%(basename)s:12: SyntaxError: Unexpected expression inside tail call
return continue new f() ;
^^^^^^^
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
// 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
"use strict";
function f() {
return 1;
}
function g() {
var x = continue f() ;
}
*%(basename)s:13: SyntaxError: Tail call expression is not allowed here
var x = continue f() ;
^^^^^^^^^^^^^
SyntaxError: Tail call expression is not allowed here
// 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: `()=>{ 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: "Unexpected token continue",
tests: [
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
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();
}
})();
// 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 --harmony-async-await
"use strict";
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: `()=>{ 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: `()=>{ function* G() { return continue foo(); } }`,
err: ` ^^^^^`,
},
{ src: `()=>{ (1, 2, 3, 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: `()=>{ let x = continue foo() }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ const c = continue foo() }`,
err: ` ^^^^^^^^^^^^^^^`,
},
{ src: `class A {}; class B extends A { constructor() { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^`,
},
{ src: `class A extends continue f () {}; }`,
err: ` ^^^^^^^^^^^^^`,
},
{ src: `async() => continue foo()`,
err: ` ^^^^^`,
},
],
},
{ msg: "Tail call expression in try block",
tests: [
{ 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: ` ^^^^^^^^^^^^^^`,
},
],
},
{ msg: "Tail call expression in catch block when finally block is also present",
tests: [
{ 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: ` ^^^^^^^^^^^^^^^^`,
},
],
},
{ msg: "Tail call expression in for-in/of body",
tests: [
{ src: `()=>{ for (var v in {a:0}) { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ for (var v of [1, 2, 3]) { return continue foo () ; } }`,
err: ` ^^^^^^^^^^^^^^^^`,
},
],
},
{ msg: "Tail call of a direct eval is not allowed",
tests: [
{ src: `()=>{ return continue eval(" foo () " ) ; }`,
err: ` ^^^^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return a || continue eval("", 1, 2) ; }`,
err: ` ^^^^^^^^^^^^^^`,
},
{ src: `()=>{ return a, continue eval ( ) ; }`,
err: ` ^^^^^^^^^`,
},
{ src: `()=> a, continue eval ( ) ; `,
err: ` ^^^^^^^^^`,
},
{ src: `()=> a || continue eval (' ' ) ; `,
err: ` ^^^^^^^^^^^^`,
},
],
},
{ msg: "Unexpected token continue",
tests: [
{ src: `()=>{ (... continue f()) => {} }`,
err: ` ^^^^^^^^`,
},
{ src: `()=>{ (a, b, c, ... continue f() ) => {} }`,
err: ` ^^^^^^^^`,
},
],
},
{ msg: "Undefined label 'foo'",
tests: [
{ src: `()=>{ continue foo () ; }`,
err: ` ^^^`,
},
],
},
];
// Should parse successfully.
var NoErrorTests = [
`()=>{ return continue a.b.c.foo () ; }`,
`()=>{ return continue a().b.c().d.foo () ; }`,
`()=>{ return continue foo (1)(2)(3, 4) ; }`,
`()=>{ return continue (0, eval)(); }`,
`()=>{ return ( continue b() ) ; }`,
"()=>{ return continue bar`ab cd ef` ; }",
"()=>{ return continue bar`ab ${cd} ef` ; }",
`()=>{ return a || continue f() ; }`,
`()=>{ return a && continue f() ; }`,
`()=>{ return a , continue f() ; }`,
`()=>{ class A { foo() { return continue super.f() ; } } }`,
`()=>{ function B() { return continue new.target() ; } }`,
`()=>{ return continue do { x ? foo() : bar() ; }() }`,
`()=>{ return continue (do { x ? foo() : bar() ; })() }`,
`()=>{ return do { 1, continue foo() } }`,
`()=>{ return do { x ? continue foo() : y } }`,
`()=>{ return a || (b && continue c()); }`,
`()=>{ return a && (b || continue c()); }`,
`()=>{ return a || (b ? c : continue d()); }`,
`()=>{ return 1, 2, 3, a || (b ? c : continue d()); }`,
`()=> continue (foo ()) ;`,
`()=> a || continue foo () ;`,
`()=> a && continue foo () ;`,
`()=> a ? continue foo () : b;`,
];
(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 {
eval(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);
src = `"use strict"; ` + src;
Realm.eval(0, src);
print("PASSED");
print();
}
})();
// 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 --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.
//
(function() {
"use strict";
function f(n) {
if (n <= 0) {
return "foo";
}
return continue f(n - 1);
}
assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
})();
(function() {
"use strict";
function f(n) {
if (n <= 0) {
return "foo";
}
return continue f(n - 1, 42); // Call with arguments adaptor.
}
assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
})();
(function() {
"use strict";
function f(n){
if (n <= 0) {
return "foo";
}
return continue g(n - 1);
}
function g(n){
if (n <= 0) {
return "bar";
}
return continue f(n - 1);
}
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
})();
(function() {
"use strict";
function f(n){
if (n <= 0) {
return "foo";
}
return continue g(n - 1, 42); // Call with arguments adaptor.
}
function g(n){
if (n <= 0) {
return "bar";
}
return continue f(n - 1, 42); // Call with arguments adaptor.
}
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
})();
//
// Tail call bound functions.
//
(function() {
"use strict";
function f0(n) {
if (n <= 0) {
return "foo";
}
return continue f_bound(n - 1);
}
var f_bound = f0.bind({});
function f(n) {
return continue f_bound(n);
}
assertEquals("foo", f(1e5));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
})();
(function() {
"use strict";
function f0(n){
if (n <= 0) {
return "foo";
}
return continue g_bound(n - 1);
}
function g0(n){
if (n <= 0) {
return "bar";
}
return continue f_bound(n - 1);
}
var f_bound = f0.bind({});
var g_bound = g0.bind({});
function f(n) {
return continue f_bound(n);
}
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
%OptimizeFunctionOnNextCall(f);
assertEquals("foo", f(1e5));
assertEquals("bar", f(1e5 + 1));
})();
// 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
"use strict";
Error.prepareStackTrace = (error,stack) => {
error.strace = stack;
return error.message + "\n at " + stack.join("\n at ");
}
function CheckStackTrace(expected) {
var e = new Error();
e.stack; // prepare stack trace
var stack = e.strace;
assertEquals("CheckStackTrace", stack[0].getFunctionName());
for (var i = 0; i < expected.length; i++) {
assertEquals(expected[i].name, stack[i + 1].getFunctionName());
}
}
%NeverOptimizeFunction(CheckStackTrace);
function f(expected_call_stack, a, b) {
CheckStackTrace(expected_call_stack);
return a;
}
function f_153(expected_call_stack, a) {
CheckStackTrace(expected_call_stack);
return 153;
}
// Tail call when caller does not have an arguments adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
CheckStackTrace([f1, test]);
return 10 + a;
}
function g1(a) { return continue f1(2); }
// Caller has more arguments than callee.
function f2(a) {
CheckStackTrace([f2, test]);
return 10 + a;
}
function g2(a, b, c) { return continue f2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
function g3(a) { return continue f3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
CheckStackTrace([f4, test]);
return 10 + a;
}
function g4(a) { return continue f4(2); }
function test() {
assertEquals(12, g1(1));
assertEquals(12, g2(1, 2, 3));
assertEquals(19, g3(1));
assertEquals(12, g4(1));
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail call when caller has an arguments adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
CheckStackTrace([f1, test]);
return 10 + a;
}
function g1(a) { return continue f1(2); }
// Caller has more arguments than callee.
function f2(a) {
CheckStackTrace([f2, test]);
return 10 + a;
}
function g2(a, b, c) { return continue f2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
function g3(a) { return continue f3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
CheckStackTrace([f4, test]);
return 10 + a;
}
function g4(a) { return continue f4(2); }
function test() {
assertEquals(12, g1());
assertEquals(12, g2());
assertEquals(19, g3());
assertEquals(12, g4());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail call bound function when caller does not have an arguments
// adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
assertEquals(153, this.a);
CheckStackTrace([f1, test]);
return 10 + a;
}
var b1 = f1.bind({a: 153});
function g1(a) { return continue b1(2); }
// Caller has more arguments than callee.
function f2(a) {
assertEquals(153, this.a);
CheckStackTrace([f2, test]);
return 10 + a;
}
var b2 = f2.bind({a: 153});
function g2(a, b, c) { return continue b2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
var b3 = f3.bind({a: 153});
function g3(a) { return continue b3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f4, test]);
return 10 + a;
}
var b4 = f4.bind({a: 153});
function g4(a) { return continue b4(2); }
function test() {
assertEquals(12, g1(1));
assertEquals(12, g2(1, 2, 3));
assertEquals(19, g3(1));
assertEquals(12, g4(1));
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Tail call bound function when caller has an arguments adaptor frame.
(function() {
// Caller and callee have same number of arguments.
function f1(a) {
assertEquals(153, this.a);
CheckStackTrace([f1, test]);
return 10 + a;
}
var b1 = f1.bind({a: 153});
function g1(a) { return continue b1(2); }
// Caller has more arguments than callee.
function f2(a) {
assertEquals(153, this.a);
CheckStackTrace([f2, test]);
return 10 + a;
}
var b2 = f2.bind({a: 153});
function g2(a, b, c) { return continue b2(2); }
// Caller has less arguments than callee.
function f3(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f3, test]);
return 10 + a + b + c;
}
var b3 = f3.bind({a: 153});
function g3(a) { return continue b3(2, 3, 4); }
// Callee has arguments adaptor frame.
function f4(a, b, c) {
assertEquals(153, this.a);
CheckStackTrace([f4, test]);
return 10 + a;
}
var b4 = f4.bind({a: 153});
function g4(a) { return continue b4(2); }
function test() {
assertEquals(12, g1());
assertEquals(12, g2());
assertEquals(19, g3());
assertEquals(12, g4());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// 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.
(function() {
function g1(a) {
return f([f, g1, test], false) || continue f([f, test], true);
}
function g2(a) {
return f([f, g2, test], true) && continue f([f, test], true);
}
function g3(a) {
return f([f, g3, test], 13), continue f([f, test], 153);
}
function g4(a) {
return f([f, g4, test], false) ||
(f([f, g4, test], true) && continue f([f, test], true));
}
function g5(a) {
return f([f, g5, test], true) &&
(f([f, g5, test], false) || continue f([f, test], true));
}
function g6(a) {
return f([f, g6, test], 13), f([f, g6, test], 42),
continue f([f, test], 153);
}
function g7(a) {
return f([f, g7, test], false) ||
(f([f, g7, test], false) ? continue f([f, test], true)
: continue f([f, test], true));
}
function g8(a) {
return f([f, g8, test], false) || f([f, g8, test], true) &&
continue f([f, test], true);
}
function g9(a) {
return f([f, g9, test], true) && f([f, g9, test], false) ||
continue f([f, test], true);
}
function g10(a) {
return f([f, g10, test], true) && f([f, g10, test], false) ||
f([f, g10, test], true) ?
f([f, g10, test], true) && f([f, g10, test], false) ||
continue f([f, test], true) :
f([f, g10, test], true) && f([f, g10, test], false) ||
continue f([f, test], true);
}
function test() {
assertEquals(true, g1());
assertEquals(true, g2());
assertEquals(153, g3());
assertEquals(true, g4());
assertEquals(true, g5());
assertEquals(153, g6());
assertEquals(true, g7());
assertEquals(true, g8());
assertEquals(true, g9());
assertEquals(true, g10());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// 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.
(function() {
function tc1(a) {
try {
f_153([f_153, tc1, test]);
return f_153([f_153, tc1, test]);
} catch(e) {
f_153([f_153, tc1, test]);
}
}
function tc2(a) {
try {
f_153([f_153, tc2, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tc2, test]);
return continue f_153([f_153, test]);
}
}
function tc3(a) {
try {
f_153([f_153, tc3, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tc3, test]);
}
f_153([f_153, tc3, test]);
return continue f_153([f_153, test]);
}
function test() {
assertEquals(153, tc1());
assertEquals(153, tc2());
assertEquals(153, tc3());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from try-finally constructs.
(function() {
function tf1(a) {
try {
f_153([f_153, tf1, test]);
return f_153([f_153, tf1, test]);
} finally {
f_153([f_153, tf1, test]);
}
}
function tf2(a) {
try {
f_153([f_153, tf2, test]);
throw new Error("boom");
} finally {
f_153([f_153, tf2, test]);
return continue f_153([f_153, test]);
}
}
function tf3(a) {
try {
f_153([f_153, tf3, test]);
} finally {
f_153([f_153, tf3, test]);
}
return continue f_153([f_153, test]);
}
function test() {
assertEquals(153, tf1());
assertEquals(153, tf2());
assertEquals(153, tf3());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from try-catch-finally constructs.
(function() {
function tcf1(a) {
try {
f_153([f_153, tcf1, test]);
return f_153([f_153, tcf1, test]);
} catch(e) {
} finally {
f_153([f_153, tcf1, test]);
}
}
function tcf2(a) {
try {
f_153([f_153, tcf2, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tcf2, test]);
return f_153([f_153, tcf2, test]);
} finally {
f_153([f_153, tcf2, test]);
}
}
function tcf3(a) {
try {
f_153([f_153, tcf3, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tcf3, test]);
} finally {
f_153([f_153, tcf3, test]);
return continue f_153([f_153, test]);
}
}
function tcf4(a) {
try {
f_153([f_153, tcf4, test]);
throw new Error("boom");
} catch(e) {
f_153([f_153, tcf4, test]);
} finally {
f_153([f_153, tcf4, test]);
}
return continue f_153([f_153, test]);
}
function test() {
assertEquals(153, tcf1());
assertEquals(153, tcf2());
assertEquals(153, tcf3());
assertEquals(153, tcf4());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from arrow functions.
(function () {
function g1(a) {
return continue (() => { return continue f_153([f_153, test]); })();
}
function g2(a) {
return continue (() => continue f_153([f_153, test]))();
}
function g3(a) {
var closure = () => f([f, closure, test], true)
? continue f_153([f_153, test])
: continue f_153([f_153, test]);
return continue closure();
}
function test() {
assertEquals(153, g1());
assertEquals(153, g2());
assertEquals(153, g3());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
// Test tail calls from do expressions.
(function () {
function g1(a) {
var a = do { return continue f_153([f_153, test]); 42; };
return a;
}
function test() {
assertEquals(153, g1());
}
test();
test();
%OptimizeFunctionOnNextCall(test);
test();
})();
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