Clarification regarding Completion Records

# Felix Kling (8 years ago)

I need some clarification around completion records.

Let me start with examples in the spec (7.0) and explain how I understand them (and what I don't understand):

12.1.6 Runtime Semantics: Evaluation

IdentifierReference: Identifier
     Return ?ResolveBinding(StringValue of Identifier).

ResolveBinding is an abstract operation which can return a completion record, but in the successful case, it returns a Reference (spec type) not a completion record. Either way, since the "IdentifierReference evaluation" algorithm is not an abstract operation, the Reference is returned, not a completion record. (Note 1 also says "The result of evaluating an IdentifierReference is always a value of type Reference.")

Now when I look at

13.5.1 Runtime Semantics: Evaluation

ExpressionStatement: Expression;
    1. Let exprRef be the result of evaluating Expression.
    2. Return ?GetValue(exprRef).

it seems to support my interpretation (exprRef must be a reference in a successful case) and I would assume that "evaluating an ExpressionStatement" also returns whatever ?GetValue(exprRef) returns, not a completion record.

But when then look at

13.2.13 Runtime Semantics: Evaluation (Block)

StatementList: StatementList StatementListItem
   1. Let sl be the result of evaluating StatementList.
   2. ReturnIfAbrupt(sl).
   3. Let s be the result of evaluating StatementListItem.
   4. Return Completion(UpdateEmpty(s, sl)).

It seems that "evaluating StatementListItem" must result in a completion record, which seems to contradict my understanding of "evaluating" something.


The only other explanation seems to be that "the result of evaluating Expression" is a completion record and exprRef is the implicitly unwrapped value according to 6.2.2.2:

Any reference to a Completion Record value that is in a context that does not explicitly require a complete Completion Record value is equivalent to an explicit reference to the [[Value]] field of the Completion Record value unless the Completion Record is an abrupt completion.

Which would mean that "evaluating an IdentifierReference" actually returns a completion record whose value is a Reference (spec type)?

And would that mean that evaluating "ExpressionStatement: Expression;" is actually performing:

2. let value be ?GetValue(exprRef).
3. return NormalCompletion(value).

Related: Is any language type always returned/passed via a normal completion record? My understanding is that an operation might not return a completion record if the return value is a specification type. But is it always a completion record if the value is a language type?

I hope at lest part of what I said is correct, thank you in advance for your help!

Felix

# Bergi (8 years ago)

Felix Kling wrote:

I need some clarification around completion records.

You'll want to have a look at the algorithmic conventions (www.ecma-international.org/ecma-262/7.0/#sec-algorithm-conventions) and the implicit coercion of completion values (www.ecma-international.org/ecma-262/7.0/#sec-implicit-completion-values):

| Calls to abstract operations return Completion Records.

| The algorithms of this specification often implicitly return | Completion Records whose [[Type]] is normal. Unless it is otherwise | obvious from the context, an algorithm statement that returns a value | that is not a Completion Record, such as: | > Return "Infinity". | means the same thing as: | > Return NormalCompletion("Infinity"). | | However, if the value expression of a “return” statement is a | Completion Record construction literal, the resulting Completion | Record is returned. If the value expression is a call to an abstract | operation, the “return” statement simply returns the Completion | Record produced by the abstract operation.

Yes, it's a bit sloppy, but makes the spec much more readable. It's already technical enough, so this does formally apply some common sense :-)

kind , Bergi

# Felix Kling (8 years ago)

I read these paragraphs over and over again ;) Maybe I just need someone to explain it to me in different words.

So to apply these to my case:

  • ResolveBinding is an "abstract operation" so it returns a completion record, whose value is a "Reference", even though completion records are only supposed to have language values as value (6.2.2) (this still confuses me)

  • As per your quote, Return ?ResolveBinding(...) simply returns that completion record.

  • In Let exprRef be the result of evaluating Expression, exprRef is a Reference, the completion record obtained by "evaluating Expression" was implicitly unwrapped, according to 6.2.2.2: *"Any reference to a Completion Record value that is in a context that does not explicitly require a complete Completion Record value is equivalent to an explicit reference to the [[Value]] field of the Completion Record value unless the Completion Record is an abrupt completion."

Am I right so far?

Then, does the sentence

The algorithms of this specification often implicitly return Completion Records whose [[Type]] is normal.

mean that

  1. Algorithms may or may not return a completion record (i.e. some do and some don't).
  2. Algorithms always return a completion record, but it's not always explicitly stated in the algorithm.

Felix

# Bergi (8 years ago)

Felix Kling wrote:

  • ResolveBinding is an "abstract operation" so it returns a completion record, whose value is a "Reference", even though completion records are only supposed to have language values as value (6.2.2) (this still confuses me)

Uh, that's weird indeed. Looks like you found a mistake.

  • As per your quote, Return ?ResolveBinding(...) simply returns that completion record.

  • In Let exprRef be the result of evaluating Expression, exprRef is a Reference, the completion record obtained by "evaluating Expression" was implicitly unwrapped, according to 6.2.2.2: *"Any reference to a Completion Record value that is in a context that does not explicitly require a complete Completion Record value is equivalent to an explicit reference to the [[Value]] field of the Completion Record value unless the Completion Record is an abrupt completion."

Am I right so far?

I believe so, yes.

Then, does the sentence

The algorithms of this specification often implicitly return Completion Records whose [[Type]] is normal.

mean that

  1. Algorithms may or may not return a completion record (i.e. some do and some don't).
  2. Algorithms always return a completion record, but it's not always explicitly stated in the algorithm.

I'd say the second. But then again, there might be some algorithms that get the [[Value]] from a completion record, and those hardly will return a completion record, would they? Take ReturnIfAbrupt as an example. It's weird.

# Michael Dyck (8 years ago)

On 16-09-23 10:24 AM, Felix Kling wrote:

I read these paragraphs over and over again ;) Maybe I just need someone to explain it to me in different words.

So to apply these to my case:

  • ResolveBinding is an "abstract operation" so it returns a completion record, whose value is a "Reference", even though completion records are only supposed to have language values as value (6.2.2) (this still confuses me)

The spec is not consistent in this area. That is, these statements are not compatible:

  • Every call to an abstract operation returns a completion record.
  • Every completion record's [[Value]] is a language value or ~empty~.
  • Some abstract operations (e.g. ResolveBinding) need to convey values to the caller that are neither language values nor ~empty~.

(See tc39/ecma262#496 for more examples, and for possible ways of resolving the inconsistency.)

  • In Let exprRef be the result of evaluating Expression, exprRef is a Reference, the completion record obtained by "evaluating Expression" was implicitly unwrapped, according to 6.2.2.2: *"Any reference to a Completion Record value that is in a context that does not explicitly require a complete Completion Record value is equivalent to an explicit reference to the [[Value]] field of the Completion Record value unless the Completion Record is an abrupt completion."

Am I right so far?

Not entirely. Here's another way to look at it. If the implicit rule of 6.2.2.2 were made explicit, we would have something like: Let exprRef be maybe-unwrap(the result of evaluating Expression).

where maybe-unwrap(cr) is a shorthand for:

  • cr, if cr is an abrupt completion, or
  • cr.[[Value]] if cr is a normal completion.

So (theoretically), for any given execution of this algorithm step, exprRef is either a Reference or an abrupt completion.

In this case, things also work if you ignore 6.2.2.2 (so that exprRef is always a Completion Record), because the subsequent call to GetValue() starts with a call to ReturnIfAbrupt(), which accomplishes the unwrapping.

Then, does the sentence

The algorithms of this specification often implicitly return Completion Records whose [[Type]] is normal.

mean that

  1. Algorithms may or may not return a completion record (i.e. some do and some don't).
  2. Algorithms always return a completion record, but it's not always explicitly stated in the algorithm.

Statement 2 would result in a similar inconsistency to the one noted above (just replacing "abstract operation" with "algorithm").

Statement 1 doesn't have that problem, but it still has the problem of fitting into the world in which the 'abstract operation' inconsistency exists.