From 52706a241e36ca85246eea2c2b14f6d2c3a70453 Mon Sep 17 00:00:00 2001 From: Michael Dyck Date: Tue, 8 Mar 2022 21:06:35 -0500 Subject: [PATCH] Change more `Completion()` to `?` (GetValue tricky) Specifically, change occurrences of: ``` 1. Let _ref_ be Completion(Evaluation of X). 1. ... ? GetValue(_ref_) ... 1. (later references to _ref_) ``` to: ``` 1. Let _ref_ be ? Evaluation of X. 1. ... ? GetValue(_ref_) ... 1. (later references to _ref_) ``` In the following case analysis, let "CR" denote the value returned by `Evaluation of X` (always a Completion Record), and, if it's a normal completion, let "V" denote the value in its [[Value]] field. Before the change: If CR is an abrupt completion: it is bound to _ref_, then passed to GetValue, which executes ReturnIfAbrupt on it, i.e. returns it from GetValue, and the `?` before GetValue returns it from the algorithm. If CR is a normal completion: _ref_ is bound to it, then passed to GetValue, which would execute ReturnIfAbrupt on it, which would unwrap it to V. The rest of GetValue then operates on V, and then, in any event, returns some completion record, not necessarily the same as CR. (Note that _ref_ remains bound to CR.) After the change: If CR is an abrupt completion: the `?` before Evaluation returns it from the algorithm. (So, the same net effect as before.) If CR is a normal completion: the `?` before Evaluation unwraps it to V, _ref_ is bound to V, then passed to GetValue. GetValue's ReturnIfAbrupt has no effect on V, and the rest of GetValue operates on V, and returns some completion record, not necessaily the same as CR. (So, the same effect as before, *except* that _ref_ is bound to V, not CR. This difference is important because of the later references to _ref_.) To summarize: if the result of `Evaluation of X` is a normal completion, then in the status quo, the later references to _ref_ are references to that Completion Record, but with this commit, they would be references to the [[Value]] of that Completion Record. However, I believe that in every case, that difference either doesn't matter, or it fixes an editorial bug. Example of "doesn't matter": In some cases, the only later reference is where _ref_ is passed to the first parameter of PutValue, which immediately calls ReturnIfAbrupt on it, so it doesn't matter if _ref_ refers to the Completion Record or its [[Value]]. Example of "fixes an editorial bug": In the Evaluation rule for `CallExpression : CoverCallExpressionAndAsyncArrowHead` the next step says: ```If _ref_ is a Reference Record, ...``` In the "Before" world, where _ref_ is bound to a Completion Record, this test is never true. Another example: In many cases, the value of _ref_ is passed (directly or indirectly) to the second parameter of EvaluateCall, which requires "an ECMAScript language value or a Reference Record". In the "Before" world, _ref_ is bound to a Completion Record, which is not what's required. Prior to the merge of PR #2547, these cases would have caused an implicit unwrapping from the Completion Record to its [[Value]], but #2547 removed the idea of implicit unwrapping, so these references have been editorial bugs since then. --- spec.html | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/spec.html b/spec.html index 6d7bf36cc48..8c859570403 100644 --- a/spec.html +++ b/spec.html @@ -19069,7 +19069,7 @@

Runtime Semantics: Evaluation

1. Let _expr_ be the |CallMemberExpression| that is covered by |CoverCallExpressionAndAsyncArrowHead|. 1. Let _memberExpr_ be the |MemberExpression| of _expr_. 1. Let _arguments_ be the |Arguments| of _expr_. - 1. Let _ref_ be Completion(Evaluation of _memberExpr_). + 1. Let _ref_ be ? Evaluation of _memberExpr_. 1. Let _func_ be ? GetValue(_ref_). 1. If _ref_ is a Reference Record, IsPropertyReference(_ref_) is *false*, and _ref_.[[ReferencedName]] is *"eval"*, then 1. If SameValue(_func_, %eval%) is *true*, then @@ -19086,7 +19086,7 @@

Runtime Semantics: Evaluation

A |CallExpression| evaluation that executes step is a direct eval.

CallExpression : CallExpression Arguments - 1. Let _ref_ be Completion(Evaluation of |CallExpression|). + 1. Let _ref_ be ? Evaluation of |CallExpression|. 1. Let _func_ be ? GetValue(_ref_). 1. Let _thisCall_ be this |CallExpression|. 1. Let _tailCall_ be IsInTailPosition(_thisCall_). @@ -19282,7 +19282,7 @@

Runtime Semantics: Evaluation

MemberExpression OptionalChain - 1. Let _baseReference_ be Completion(Evaluation of |MemberExpression|). + 1. Let _baseReference_ be ? Evaluation of |MemberExpression|. 1. Let _baseValue_ be ? GetValue(_baseReference_). 1. If _baseValue_ is *undefined* or *null*, then 1. Return *undefined*. @@ -19293,7 +19293,7 @@

Runtime Semantics: Evaluation

CallExpression OptionalChain - 1. Let _baseReference_ be Completion(Evaluation of |CallExpression|). + 1. Let _baseReference_ be ? Evaluation of |CallExpression|. 1. Let _baseValue_ be ? GetValue(_baseReference_). 1. If _baseValue_ is *undefined* or *null*, then 1. Return *undefined*. @@ -19304,7 +19304,7 @@

Runtime Semantics: Evaluation

OptionalExpression OptionalChain - 1. Let _baseReference_ be Completion(Evaluation of |OptionalExpression|). + 1. Let _baseReference_ be ? Evaluation of |OptionalExpression|. 1. Let _baseValue_ be ? GetValue(_baseReference_). 1. If _baseValue_ is *undefined* or *null*, then 1. Return *undefined*. @@ -19408,7 +19408,7 @@

Tagged Templates

Runtime Semantics: Evaluation

MemberExpression : MemberExpression TemplateLiteral - 1. Let _tagRef_ be Completion(Evaluation of |MemberExpression|). + 1. Let _tagRef_ be ? Evaluation of |MemberExpression|. 1. Let _tagFunc_ be ? GetValue(_tagRef_). 1. Let _thisCall_ be this |MemberExpression|. 1. Let _tailCall_ be IsInTailPosition(_thisCall_). @@ -19416,7 +19416,7 @@

Runtime Semantics: Evaluation

CallExpression : CallExpression TemplateLiteral - 1. Let _tagRef_ be Completion(Evaluation of |CallExpression|). + 1. Let _tagRef_ be ? Evaluation of |CallExpression|. 1. Let _tagFunc_ be ? GetValue(_tagRef_). 1. Let _thisCall_ be this |CallExpression|. 1. Let _tailCall_ be IsInTailPosition(_thisCall_). @@ -19543,7 +19543,7 @@

Postfix Increment Operator

Runtime Semantics: Evaluation

UpdateExpression : LeftHandSideExpression `++` - 1. Let _lhs_ be Completion(Evaluation of |LeftHandSideExpression|). + 1. Let _lhs_ be ? Evaluation of |LeftHandSideExpression|. 1. Let _oldValue_ be ? ToNumeric(? GetValue(_lhs_)). 1. If Type(_oldValue_) is Number, then 1. Let _newValue_ be Number::add(_oldValue_, *1*𝔽). @@ -19563,7 +19563,7 @@

Postfix Decrement Operator

Runtime Semantics: Evaluation

UpdateExpression : LeftHandSideExpression `--` - 1. Let _lhs_ be Completion(Evaluation of |LeftHandSideExpression|). + 1. Let _lhs_ be ? Evaluation of |LeftHandSideExpression|. 1. Let _oldValue_ be ? ToNumeric(? GetValue(_lhs_)). 1. If Type(_oldValue_) is Number, then 1. Let _newValue_ be Number::subtract(_oldValue_, *1*𝔽). @@ -19583,7 +19583,7 @@

Prefix Increment Operator

Runtime Semantics: Evaluation

UpdateExpression : `++` UnaryExpression - 1. Let _expr_ be Completion(Evaluation of |UnaryExpression|). + 1. Let _expr_ be ? Evaluation of |UnaryExpression|. 1. Let _oldValue_ be ? ToNumeric(? GetValue(_expr_)). 1. If Type(_oldValue_) is Number, then 1. Let _newValue_ be Number::add(_oldValue_, *1*𝔽). @@ -19603,7 +19603,7 @@

Prefix Decrement Operator

Runtime Semantics: Evaluation

UpdateExpression : `--` UnaryExpression - 1. Let _expr_ be Completion(Evaluation of |UnaryExpression|). + 1. Let _expr_ be ? Evaluation of |UnaryExpression|. 1. Let _oldValue_ be ? ToNumeric(? GetValue(_expr_)). 1. If Type(_oldValue_) is Number, then 1. Let _newValue_ be Number::subtract(_oldValue_, *1*𝔽). @@ -20426,7 +20426,7 @@

Runtime Semantics: Evaluation

AssignmentExpression : LeftHandSideExpression AssignmentOperator AssignmentExpression - 1. Let _lref_ be Completion(Evaluation of |LeftHandSideExpression|). + 1. Let _lref_ be ? Evaluation of |LeftHandSideExpression|. 1. [id="step-assignmentexpression-evaluation-compound-getvalue"] Let _lval_ be ? GetValue(_lref_). 1. Let _rref_ be Completion(Evaluation of |AssignmentExpression|). 1. Let _rval_ be ? GetValue(_rref_). @@ -20456,7 +20456,7 @@

Runtime Semantics: Evaluation

AssignmentExpression : LeftHandSideExpression `&&=` AssignmentExpression - 1. Let _lref_ be Completion(Evaluation of |LeftHandSideExpression|). + 1. Let _lref_ be ? Evaluation of |LeftHandSideExpression|. 1. [id="step-assignmentexpression-evaluation-lgcl-and-getvalue"] Let _lval_ be ? GetValue(_lref_). 1. Let _lbool_ be ToBoolean(_lval_). 1. If _lbool_ is *false*, return _lval_. @@ -20470,7 +20470,7 @@

Runtime Semantics: Evaluation

AssignmentExpression : LeftHandSideExpression `||=` AssignmentExpression - 1. Let _lref_ be Completion(Evaluation of |LeftHandSideExpression|). + 1. Let _lref_ be ? Evaluation of |LeftHandSideExpression|. 1. [id="step-assignmentexpression-evaluation-lgcl-or-getvalue"] Let _lval_ be ? GetValue(_lref_). 1. Let _lbool_ be ToBoolean(_lval_). 1. If _lbool_ is *true*, return _lval_. @@ -20484,7 +20484,7 @@

Runtime Semantics: Evaluation

AssignmentExpression : LeftHandSideExpression `??=` AssignmentExpression - 1. Let _lref_ be Completion(Evaluation of |LeftHandSideExpression|). + 1. Let _lref_ be ? Evaluation of |LeftHandSideExpression|. 1. [id="step-assignmentexpression-evaluation-lgcl-nullish-getvalue"] Let _lval_ be ? GetValue(_lref_). 1. If _lval_ is neither *undefined* nor *null*, return _lval_. 1. If IsAnonymousFunctionDefinition(|AssignmentExpression|) is *true* and IsIdentifierRef of |LeftHandSideExpression| is *true*, then