Stage 0 Draft / May 24, 2016

Syntactic Tail Calls

This document introduces explicit syntax for tail calls. For motivation and an introduction, see the explainer document. The specification here defines the grammar for explicit tail calls and the runtime semantics which guarantee tail call elimination for explicit tail call sites and removes guaranteed tail call elimination from the cases where it was implicitly supported in ES2015. This specification still permits tail call elimination in other cases, but does not require it.

Examples##

The following examples are all syntactically valid:

function foo1() { return continue bar(); }
function foo2() { return continue bar`template`; }
function foo3() { return bool ? continue bar() : baz }

let foo4 = () => continue foo();
let foo5 = () => bool ? continue bar() : baz;

The following examples are all syntax errors:

continue bar();
// continue in a statement context is still a ContinueStatement.

(continue bar());
// continue is only syntactically valid under a return statement

function foo1() { return continue baz; }
function foo2() { return continue 1 + baz() }
function foo3() { return continue baz(), 1 }
// things that aren't tail calls are syntax errors

1Tail Calls#

Syntax

AssignmentExpression[In, Yield]:ConditionalExpression[?In, ?Yield] [+Yield]YieldExpression[?In] ArrowFunction[?In, ?Yield] LeftHandSideExpression[?Yield]=AssignmentExpression[?In, ?Yield] LeftHandSideExpression[?Yield]AssignmentOperatorAssignmentExpression[?In, ?Yield] TailCallExpression[?Yield] TailCallExpression[Yield]:continueMemberExpression[?Yield]Arguments[?Yield] continueCallExpression[?Yield]Arguments[?Yield] continueMemberExpression[?Yield]TemplateLiteral[?Yield] continueCallExpression[?Yield]TemplateLiteral[?Yield]

1.1Static Semantics: Early Errors#

1.2Runtime Semantics: Evaluation#

TailCallExpression:continueMemberExpressionArguments
  1. Let ref be the result of evaluating MemberExpression.
  2. Let func be ? GetValue(ref).
  3. If Type(ref) is Reference, then
    1. If IsPropertyReference(ref) is true, then
      1. Let thisValue be GetThisValue(ref).
    2. Else, the base of ref is an Environment Record
      1. Let refEnv be GetBase(ref).
      2. Let thisValue be refEnv.WithBaseObject().
  4. Else Type(ref) is not Reference,
    1. Let thisValue be undefined.
  5. Return ? EvaluateDirectCall(func, thisValue, Arguments, true).
TailCallExpression:continueCallExpressionArguments
  1. Let ref be the result of evaluating CallExpression.
  2. Return ? EvaluateCall(ref, Arguments, true).
TailCallExpression:continueMemberExpressionTemplateLiteral
  1. Let tagRef be the result of evaluating MemberExpression.
  2. Return ? EvaluateCall(tagRef, TemplateLiteral, true).
TailCallExpression:continueCallExpressionTemplateLiteral
  1. Let tagRef be the result of evaluating CallExpression.
  2. Return ? EvaluateCall(tagRef, TemplateLiteral, true).

2Modifications to existing algorithms#

2.1Function Calls#

2.1.1Runtime Semantics: Evaluation#

CallExpression:MemberExpressionArguments
  1. Let ref be the result of evaluating MemberExpression.
  2. Let func be ? GetValue(ref).
  3. If Type(ref) is Reference and IsPropertyReference(ref) is false and GetReferencedName(ref) is "eval", then
    1. If SameValue(func, %eval%) is true, then
      1. Let argList be ? ArgumentListEvaluation(Arguments).
      2. If argList has no elements, return undefined.
      3. Let evalText be the first element of argList.
      4. If the source code matching this CallExpression is strict code, let strictCaller be true. Otherwise let strictCaller be false.
      5. Let evalRealm be the current Realm Record.
      6. Perform ? HostEnsureCanCompileStrings(evalRealm, evalRealm).
      7. Return ? PerformEval(evalText, evalRealm, strictCaller, true).
  4. If Type(ref) is Reference, then
    1. If IsPropertyReference(ref) is true, then
      1. Let thisValue be GetThisValue(ref).
    2. Else, the base of ref is an Environment Record
      1. Let refEnv be GetBase(ref).
      2. Let thisValue be refEnv.WithBaseObject().
  5. Else Type(ref) is not Reference,
    1. Let thisValue be undefined.
  6. Let thisCall be this CallExpression.
  7. Let tailCall be IsInTailPosition(thisCall).
  8. Return ? EvaluateDirectCall(func, thisValue, Arguments, tailCallfalse).

A CallExpression evaluation that executes step 3.a.vi is a direct eval.

CallExpression:CallExpressionArguments
  1. Let ref be the result of evaluating CallExpression.
  2. Let thisCall be this CallExpression.
  3. Let tailCall be IsInTailPosition(thisCall).
  4. Return ? EvaluateCall(ref, Arguments, tailCallfalse).

2.2Tagged Templates#

2.2.1Runtime Semantics: Evaluation#

MemberExpression:MemberExpressionTemplateLiteral
  1. Let tagRef be the result of evaluating MemberExpression.
  2. Let thisCall be this CallExpression.
  3. Let tailCall be IsInTailPosition(thisCall).
  4. Return ? EvaluateCall(tagRef, TemplateLiteral, tailCallfalse).
CallExpression:CallExpressionTemplateLiteral
  1. Let tagRef be the result of evaluating CallExpression.
  2. Let thisCall be this CallExpression.
  3. Let tailCall be IsInTailPosition(thisCall).
  4. Return ? EvaluateCall(tagRef, TemplateLiteral, tailCallfalse).

2.3Static Semantics: HasProductionInTailPosition#

With parameter nonterminal.

2.3.1Expression Rules#

Note

A potential tail position call that is immediately followed by return GetValue of the call result is also a possible tail position call. Function calls cannot return reference values, so such a GetValue operation will always returns the same value as the actual function call result.

AssignmentExpression:YieldExpression ArrowFunction LeftHandSideExpression=AssignmentExpression LeftHandSideExpressionAssignmentOperatorAssignmentExpression BitwiseANDExpression:BitwiseANDExpression&EqualityExpression BitwiseXORExpression:BitwiseXORExpression^BitwiseANDExpression BitwiseORExpression:BitwiseORExpression|BitwiseXORExpression EqualityExpression:EqualityExpression==RelationalExpression EqualityExpression!=RelationalExpression EqualityExpression===RelationalExpression EqualityExpression!==RelationalExpression RelationalExpression:RelationalExpression<ShiftExpression RelationalExpression>ShiftExpression RelationalExpression<=ShiftExpression RelationalExpression>=ShiftExpression RelationalExpressioninstanceofShiftExpression RelationalExpressioninShiftExpression ShiftExpression:ShiftExpression<<AdditiveExpression ShiftExpression>>AdditiveExpression ShiftExpression>>>AdditiveExpression AdditiveExpression:AdditiveExpression+MultiplicativeExpression AdditiveExpression-MultiplicativeExpression MultiplicativeExpression:MultiplicativeExpressionMultiplicativeOperatorExponentiationExpression ExponentiationExpression:UpdateExpression**ExponentiationExpression UpdateExpression:LeftHandSideExpression++ LeftHandSideExpression-- ++UnaryExpression --UnaryExpression UnaryExpression:deleteUnaryExpression voidUnaryExpression typeofUnaryExpression +UnaryExpression -UnaryExpression ~UnaryExpression !UnaryExpression CallExpression:SuperCall CallExpression[Expression] CallExpression.IdentifierName NewExpression:newNewExpression MemberExpression:MemberExpression[Expression] MemberExpression.IdentifierName SuperProperty MetaProperty newMemberExpressionArguments PrimaryExpression:this IdentifierReference Literal ArrayLiteral ObjectLiteral FunctionExpression ClassExpression GeneratorExpression RegularExpressionLiteral TemplateLiteral
  1. Return false.
Expression:AssignmentExpression Expression,AssignmentExpression
  1. Return HasProductionInTailPosition of AssignmentExpression with argument nonterminal.
ConditionalExpression:LogicalORExpression?AssignmentExpression:AssignmentExpression
  1. Let has be HasProductionInTailPosition of the first AssignmentExpression with argument nonterminal.
  2. If has is true, return true.
  3. Return HasProductionInTailPosition of the second AssignmentExpression with argument nonterminal.
LogicalANDExpression:LogicalANDExpression&&BitwiseORExpression
  1. Return HasProductionInTailPosition of BitwiseORExpression with argument nonterminal.
LogicalORExpression:LogicalORExpression||LogicalANDExpression
  1. Return HasProductionInTailPosition of LogicalANDExpression with argument nonterminal.
CallExpression:MemberExpressionArguments CallExpressionArguments CallExpressionTemplateLiteral
  1. If this CallExpression is nonterminal, return true.
  2. Return false.
MemberExpression:MemberExpressionTemplateLiteral
  1. If this MemberExpression is nonterminal, return true.
  2. Return false.
PrimaryExpression:CoverParenthesizedExpressionAndArrowParameterList
  1. Let expr be CoveredParenthesizedExpression of CoverParenthesizedExpressionAndArrowParameterList.
  2. Return HasProductionInTailPosition of expr with argument nonterminal.
ParenthesizedExpression:(Expression)
  1. Return HasProductionInTailPosition of Expression with argument nonterminal.
TailCallExpression[Yield]:continueMemberExpression[?Yield]Arguments[?Yield] continueCallExpression[?Yield]Arguments[?Yield] continueMemberExpression[?Yield]TemplateLiteral[?Yield] continueCallExpression[?Yield]TemplateLiteral[?Yield]
  1. If this TailCallExpression is nonterminal, return true.
  2. Return false.

ACopyright & Software License#

Copyright Notice

© 2016 Brian Terlson, Eric Faust

Software License

All Software contained in this document ("Software") is protected by copyright and is being made available under the "BSD License", included below. This Software may be subject to third party rights (rights from parties other than Ecma International), including patent rights, and no licenses under such third party rights are granted under this license even if the third party concerned is a member of Ecma International. SEE THE ECMA CODE OF CONDUCT IN PATENT MATTERS AVAILABLE AT http://www.ecma-international.org/memento/codeofconduct.htm FOR INFORMATION REGARDING THE LICENSING OF PATENT CLAIMS THAT ARE REQUIRED TO IMPLEMENT ECMA INTERNATIONAL STANDARDS.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the authors nor Ecma International may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE ECMA INTERNATIONAL "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ECMA INTERNATIONAL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.