ECMAScript® 2024 Language Specification

Draft ECMA-262 / February 15, 2024

15.10 Tail Position Calls

15.10.1 Static Semantics: IsInTailPosition ( call )

The abstract operation IsInTailPosition takes argument call (a CallExpression Parse Node, a MemberExpression Parse Node, or an OptionalChain Parse Node) and returns a Boolean. It performs the following steps when called:

  1. If the source text matched by call is non-strict code, return false.
  2. If call is not contained within a FunctionBody, a ConciseBody, or an AsyncConciseBody, return false.
  3. Let body be the FunctionBody, ConciseBody, or AsyncConciseBody that most closely contains call.
  4. If body is the FunctionBody of a GeneratorBody, return false.
  5. If body is the FunctionBody of an AsyncFunctionBody, return false.
  6. If body is the FunctionBody of an AsyncGeneratorBody, return false.
  7. If body is an AsyncConciseBody, return false.
  8. Return the result of HasCallInTailPosition of body with argument call.
Note

Tail Position calls are only defined in strict mode code because of a common non-standard language extension (see 10.2.4) that enables observation of the chain of caller contexts.

15.10.2 Static Semantics: HasCallInTailPosition

The syntax-directed operation HasCallInTailPosition takes argument call (a CallExpression Parse Node, a MemberExpression Parse Node, or an OptionalChain Parse Node) and returns a Boolean.

Note 1

call is a Parse Node that represents a specific range of source text. When the following algorithms compare call to another Parse Node, it is a test of whether they represent the same source text.

Note 2

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

It is defined piecewise over the following productions:

StatementList : StatementList StatementListItem
  1. Let has be HasCallInTailPosition of StatementList with argument call.
  2. If has is true, return true.
  3. Return HasCallInTailPosition of StatementListItem with argument call.
FunctionStatementList : [empty] StatementListItem : Declaration Statement : VariableStatement EmptyStatement ExpressionStatement ContinueStatement BreakStatement ThrowStatement DebuggerStatement Block : { } ReturnStatement : return ; LabelledItem : FunctionDeclaration ForInOfStatement : for ( LeftHandSideExpression of AssignmentExpression ) Statement for ( var ForBinding of AssignmentExpression ) Statement for ( ForDeclaration of AssignmentExpression ) Statement CaseBlock : { }
  1. Return false.
IfStatement : if ( Expression ) Statement else Statement
  1. Let has be HasCallInTailPosition of the first Statement with argument call.
  2. If has is true, return true.
  3. Return HasCallInTailPosition of the second Statement with argument call.
IfStatement : if ( Expression ) Statement DoWhileStatement : do Statement while ( Expression ) ; WhileStatement : while ( Expression ) Statement ForStatement : for ( Expressionopt ; Expressionopt ; Expressionopt ) Statement for ( var VariableDeclarationList ; Expressionopt ; Expressionopt ) Statement for ( LexicalDeclaration Expressionopt ; Expressionopt ) Statement ForInOfStatement : for ( LeftHandSideExpression in Expression ) Statement for ( var ForBinding in Expression ) Statement for ( ForDeclaration in Expression ) Statement WithStatement : with ( Expression ) Statement
  1. Return HasCallInTailPosition of Statement with argument call.
LabelledStatement : LabelIdentifier : LabelledItem
  1. Return HasCallInTailPosition of LabelledItem with argument call.
ReturnStatement : return Expression ;
  1. Return HasCallInTailPosition of Expression with argument call.
SwitchStatement : switch ( Expression ) CaseBlock
  1. Return HasCallInTailPosition of CaseBlock with argument call.
CaseBlock : { CaseClausesopt DefaultClause CaseClausesopt }
  1. Let has be false.
  2. If the first CaseClauses is present, set has to HasCallInTailPosition of the first CaseClauses with argument call.
  3. If has is true, return true.
  4. Set has to HasCallInTailPosition of DefaultClause with argument call.
  5. If has is true, return true.
  6. If the second CaseClauses is present, set has to HasCallInTailPosition of the second CaseClauses with argument call.
  7. Return has.
CaseClauses : CaseClauses CaseClause
  1. Let has be HasCallInTailPosition of CaseClauses with argument call.
  2. If has is true, return true.
  3. Return HasCallInTailPosition of CaseClause with argument call.
CaseClause : case Expression : StatementListopt DefaultClause : default : StatementListopt
  1. If StatementList is present, return HasCallInTailPosition of StatementList with argument call.
  2. Return false.
TryStatement : try Block Catch
  1. Return HasCallInTailPosition of Catch with argument call.
TryStatement : try Block Finally try Block Catch Finally
  1. Return HasCallInTailPosition of Finally with argument call.
Catch : catch ( CatchParameter ) Block
  1. Return HasCallInTailPosition of Block with argument call.
AssignmentExpression : YieldExpression ArrowFunction AsyncArrowFunction LeftHandSideExpression = AssignmentExpression LeftHandSideExpression AssignmentOperator AssignmentExpression LeftHandSideExpression &&= AssignmentExpression LeftHandSideExpression ||= AssignmentExpression LeftHandSideExpression ??= AssignmentExpression 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 RelationalExpression instanceof ShiftExpression RelationalExpression in ShiftExpression PrivateIdentifier in ShiftExpression ShiftExpression : ShiftExpression << AdditiveExpression ShiftExpression >> AdditiveExpression ShiftExpression >>> AdditiveExpression AdditiveExpression : AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpression MultiplicativeExpression : MultiplicativeExpression MultiplicativeOperator ExponentiationExpression ExponentiationExpression : UpdateExpression ** ExponentiationExpression UpdateExpression : LeftHandSideExpression ++ LeftHandSideExpression -- ++ UnaryExpression -- UnaryExpression UnaryExpression : delete UnaryExpression void UnaryExpression typeof UnaryExpression + UnaryExpression - UnaryExpression ~ UnaryExpression ! UnaryExpression AwaitExpression CallExpression : SuperCall ImportCall CallExpression [ Expression ] CallExpression . IdentifierName CallExpression . PrivateIdentifier NewExpression : new NewExpression MemberExpression : MemberExpression [ Expression ] MemberExpression . IdentifierName SuperProperty MetaProperty new MemberExpression Arguments MemberExpression . PrivateIdentifier PrimaryExpression : this IdentifierReference Literal ArrayLiteral ObjectLiteral FunctionExpression ClassExpression GeneratorExpression AsyncFunctionExpression AsyncGeneratorExpression RegularExpressionLiteral TemplateLiteral
  1. Return false.
Expression : AssignmentExpression Expression , AssignmentExpression
  1. Return HasCallInTailPosition of AssignmentExpression with argument call.
ConditionalExpression : ShortCircuitExpression ? AssignmentExpression : AssignmentExpression
  1. Let has be HasCallInTailPosition of the first AssignmentExpression with argument call.
  2. If has is true, return true.
  3. Return HasCallInTailPosition of the second AssignmentExpression with argument call.
LogicalANDExpression : LogicalANDExpression && BitwiseORExpression
  1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
LogicalORExpression : LogicalORExpression || LogicalANDExpression
  1. Return HasCallInTailPosition of LogicalANDExpression with argument call.
CoalesceExpression : CoalesceExpressionHead ?? BitwiseORExpression
  1. Return HasCallInTailPosition of BitwiseORExpression with argument call.
CallExpression : CoverCallExpressionAndAsyncArrowHead CallExpression Arguments CallExpression TemplateLiteral
  1. If this CallExpression is call, return true.
  2. Return false.
OptionalExpression : MemberExpression OptionalChain CallExpression OptionalChain OptionalExpression OptionalChain
  1. Return HasCallInTailPosition of OptionalChain with argument call.
OptionalChain : ?. [ Expression ] ?. IdentifierName ?. PrivateIdentifier OptionalChain [ Expression ] OptionalChain . IdentifierName OptionalChain . PrivateIdentifier
  1. Return false.
OptionalChain : ?. Arguments OptionalChain Arguments
  1. If this OptionalChain is call, return true.
  2. Return false.
MemberExpression : MemberExpression TemplateLiteral
  1. If this MemberExpression is call, return true.
  2. Return false.
PrimaryExpression : CoverParenthesizedExpressionAndArrowParameterList
  1. Let expr be the ParenthesizedExpression that is covered by CoverParenthesizedExpressionAndArrowParameterList.
  2. Return HasCallInTailPosition of expr with argument call.
ParenthesizedExpression : ( Expression )
  1. Return HasCallInTailPosition of Expression with argument call.

15.10.3 PrepareForTailCall ( )

The abstract operation PrepareForTailCall takes no arguments and returns unused. It performs the following steps when called:

  1. Assert: The current execution context will not subsequently be used for the evaluation of any ECMAScript code or built-in functions. The invocation of Call subsequent to the invocation of this abstract operation will create and push a new execution context before performing any such evaluation.
  2. Discard all resources associated with the current execution context.
  3. Return unused.

A tail position call must either release any transient internal resources associated with the currently executing function execution context before invoking the target function or reuse those resources in support of the target function.

Note

For example, a tail position call should only grow an implementation's activation record stack by the amount that the size of the target function's activation record exceeds the size of the calling function's activation record. If the target function's activation record is smaller, then the total size of the stack should decrease.