[parser] Push variables of non-arrow parenthesized expression to parent

Parenthesized variable names are valid references for assignment. To make sure
we can properly mark the variable as assigned, we should push parenthesized
variables to the outer expression scope after the parenthesized expression is
guaranteed to not be an arrow head; so that the variable list of the parent is
complete.

Technically we could probably get by with simply pushing a single variable,
since more complex expressions aren't valid parenthesized assignment targets:
(a) = ... and [(a),(b)] = ... are valid, but ([a,b]) = ... isn't.
It doesn't really seem worth it though.

Bug: chromium:1015372
Change-Id: I095c35126742a14d0171537b9795f7258c33ab4d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1872389
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Dan Elphick <delphick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64455}
This commit is contained in:
Toon Verwaest 2019-10-21 17:37:55 +02:00 committed by Commit Bot
parent 1deefe5edd
commit 7ff8299231
2 changed files with 64 additions and 4 deletions

View File

@ -66,6 +66,24 @@ class ExpressionScope {
return result;
}
void MergeVariableList(
ScopedList<std::pair<VariableProxy*, int>>* variable_list) {
if (!CanBeExpression()) return;
// Merged variables come from a CanBeDeclaration expression scope, and
// weren't added as unresolved references to the variable scope yet. Add
// them to the variable scope on the boundary where it becomes clear they
// aren't declarations. We explicitly delay declaring the variables up to
// that point to avoid trying to add them to the unresolved list multiple
// times, e.g., for (((a))).
if (!CanBeDeclaration()) {
for (auto& proxy_initializer_pair : *variable_list) {
VariableProxy* proxy = proxy_initializer_pair.first;
this->parser()->scope()->AddUnresolved(proxy);
}
}
variable_list->MergeInto(AsExpressionParsingScope()->variable_list());
}
Variable* Declare(const AstRawString* name, int pos = kNoSourcePosition) {
if (type_ == kParameterDeclaration) {
return AsParameterDeclarationParsingScope()->Declare(name, pos);
@ -724,10 +742,7 @@ class ArrowHeadParsingScope : public ExpressionParsingScope<Types> {
// references.
this->parser()->next_arrow_function_info_.ClearStrictParameterError();
ExpressionParsingScope<Types>::ValidateExpression();
for (auto& proxy_initializer_pair : *this->variable_list()) {
VariableProxy* proxy = proxy_initializer_pair.first;
this->parser()->scope()->AddUnresolved(proxy);
}
this->parent()->MergeVariableList(this->variable_list());
}
DeclarationScope* ValidateAndCreateScope() {

View File

@ -0,0 +1,45 @@
// Copyright 2019 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
(function() {
function opt(flag) {
function inline() {
(function () {
flag()
})();
(flag) = 1;
}
inline();
}
assertThrows(opt, TypeError);
})();
(function() {
function opt(flag){
function inline() {
var f = (function() {
return flag;
});
function g(x) {
(flag) = x;
}
return [f,g];
}
return inline();
}
[f, g] = opt(1);
%PrepareFunctionForOptimization(f);
assertEquals(1, f());
assertEquals(1, f());
%OptimizeFunctionOnNextCall(f);
assertEquals(1, f());
g(2);
assertEquals(2, f());
})();