Skip to content

Commit 9be1328

Browse files
alexmarkovCommit Queue
authored and
Commit Queue
committed
[vm] Support multiple local variables with the same name in the same scope
When lowering patterns, front-end can add multiple distinct local variables with the same name into the same local scope. Previously, VM identified local variables in a local scope by name. However, this no longer works with patterns. With this change, local variables are now identified by pair (name, kernel offset). Name is still taken into account as compiler can add extra variables which do not correspond to kernel variables, such as 'this'. TEST=runtime/tests/vm/dart/regress_51091_test.dart Fixes #51091 Issue #49755 Change-Id: I0263769cb31f3f8d9652f5d6534800510ac882fb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279650 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent 252015b commit 9be1328

15 files changed

+228
-117
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Regression test for https://github.com/dart-lang/sdk/issues/51091.
6+
// Verifies that compiler doesn't crash if there are two local
7+
// variables with the same name in the same local scope.
8+
9+
// SharedOptions=--enable-experiment=patterns
10+
11+
import 'package:expect/expect.dart';
12+
13+
void test1() {
14+
if (0 case var x) {
15+
Expect.equals(0, x);
16+
}
17+
var x = 1;
18+
Expect.equals(1, x);
19+
}
20+
21+
void test2(int arg) {
22+
switch(arg) {
23+
case == 0 && var x:
24+
Expect.equals(0, x);
25+
case == 1 && var x:
26+
Expect.equals(1, x);
27+
}
28+
var x = 1;
29+
Expect.equals(1, x);
30+
}
31+
32+
void main() {
33+
test1();
34+
test2(0);
35+
test2(1);
36+
}

runtime/vm/compiler/backend/il_test_helper.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -291,10 +291,10 @@ class FlowGraphBuilderHelper {
291291
void AddVariable(const char* name,
292292
const AbstractType& static_type,
293293
CompileType* param_type = nullptr) {
294-
LocalVariable* v =
295-
new LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
296-
String::Handle(Symbols::New(Thread::Current(), name)),
297-
static_type, param_type);
294+
LocalVariable* v = new LocalVariable(
295+
TokenPosition::kNoSource, TokenPosition::kNoSource,
296+
String::Handle(Symbols::New(Thread::Current(), name)), static_type,
297+
LocalVariable::kNoKernelOffset, param_type);
298298
v->set_type_check_mode(LocalVariable::kTypeCheckedByCaller);
299299
flow_graph()->parsed_function().scope()->AddVariable(v);
300300
}

runtime/vm/compiler/compiler_state.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ LocalVariable* CompilerState::GetDummyCapturedVariable(intptr_t context_id,
4848
Z, Symbols::NewFormatted(thread(), ":context_var%" Pd, index));
4949
LocalVariable* var = new (Z)
5050
LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
51-
name, dynamic_type, /*param_type=*/nullptr);
51+
name, dynamic_type, LocalVariable::kNoKernelOffset,
52+
/*param_type=*/nullptr);
5253
var->set_is_captured();
5354
var->set_index(VariableIndex(index));
5455
return var;

runtime/vm/compiler/frontend/kernel_to_il.cc

+4-3
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ Fragment FlowGraphBuilder::ThrowNoSuchMethodError(const Function& target,
771771
LocalVariable* FlowGraphBuilder::LookupVariable(intptr_t kernel_offset) {
772772
LocalVariable* local = scopes_->locals.Lookup(kernel_offset);
773773
ASSERT(local != NULL);
774+
ASSERT(local->kernel_offset() == kernel_offset);
774775
return local;
775776
}
776777

@@ -1740,9 +1741,9 @@ static const LocalScope* MakeImplicitClosureScope(Zone* Z, const Class& klass) {
17401741
// and not the signature type.
17411742
Type& klass_type = Type::ZoneHandle(Z, klass.DeclarationType());
17421743

1743-
LocalVariable* receiver_variable = new (Z)
1744-
LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1745-
Symbols::This(), klass_type, /*param_type=*/nullptr);
1744+
LocalVariable* receiver_variable = new (Z) LocalVariable(
1745+
TokenPosition::kNoSource, TokenPosition::kNoSource, Symbols::This(),
1746+
klass_type, LocalVariable::kNoKernelOffset, /*param_type=*/nullptr);
17461747

17471748
receiver_variable->set_is_captured();
17481749
// receiver_variable->set_is_final();

runtime/vm/compiler/frontend/scope_builder.cc

+31-32
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() {
278278
TokenPosition::kNoSource, TokenPosition::kNoSource,
279279
Symbols::Value(),
280280
AbstractType::ZoneHandle(Z, function.ParameterTypeAt(pos)),
281-
&parameter_type);
281+
LocalVariable::kNoKernelOffset, &parameter_type);
282282
} else {
283283
result_->setter_value = MakeVariable(
284284
TokenPosition::kNoSource, TokenPosition::kNoSource,
@@ -577,12 +577,12 @@ void ScopeBuilder::VisitFunctionNode() {
577577
// Mark known chained futures such as _Future::timeout()'s _future.
578578
if (function.recognized_kind() == MethodRecognizer::kFutureTimeout &&
579579
depth_.function_ == 1) {
580-
LocalVariable* future = scope_->LookupVariable(Symbols::_future(), true);
580+
LocalVariable* future = scope_->LookupVariableByName(Symbols::_future());
581581
ASSERT(future != nullptr);
582582
future->set_is_chained_future();
583583
} else if (function.recognized_kind() == MethodRecognizer::kFutureWait &&
584584
depth_.function_ == 1) {
585-
LocalVariable* future = scope_->LookupVariable(Symbols::_future(), true);
585+
LocalVariable* future = scope_->LookupVariableByName(Symbols::_future());
586586
ASSERT(future != nullptr);
587587
future->set_is_chained_future();
588588
}
@@ -1311,7 +1311,8 @@ void ScopeBuilder::VisitArguments() {
13111311
void ScopeBuilder::VisitVariableDeclaration() {
13121312
PositionScope scope(&helper_.reader_);
13131313

1314-
intptr_t kernel_offset_no_tag = helper_.ReaderOffset();
1314+
const intptr_t kernel_offset =
1315+
helper_.data_program_offset_ + helper_.ReaderOffset();
13151316
VariableDeclarationHelper helper(&helper_);
13161317
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
13171318
AbstractType& type = BuildAndVisitVariableType();
@@ -1336,7 +1337,7 @@ void ScopeBuilder::VisitVariableDeclaration() {
13361337
end_position = end_position.Next();
13371338
}
13381339
LocalVariable* variable =
1339-
MakeVariable(helper.position_, end_position, name, type);
1340+
MakeVariable(helper.position_, end_position, name, type, kernel_offset);
13401341
if (helper.IsFinal()) {
13411342
variable->set_is_final();
13421343
}
@@ -1346,8 +1347,7 @@ void ScopeBuilder::VisitVariableDeclaration() {
13461347
}
13471348

13481349
scope_->AddVariable(variable);
1349-
result_->locals.Insert(helper_.data_program_offset_ + kernel_offset_no_tag,
1350-
variable);
1350+
result_->locals.Insert(kernel_offset, variable);
13511351
}
13521352

13531353
AbstractType& ScopeBuilder::BuildAndVisitVariableType() {
@@ -1486,7 +1486,8 @@ void ScopeBuilder::VisitTypeParameterType() {
14861486
// The type argument vector is passed as the very first argument to the
14871487
// factory constructor function.
14881488
HandleSpecialLoad(&result_->type_arguments_variable,
1489-
Symbols::TypeArgumentsParameter());
1489+
Symbols::TypeArgumentsParameter(),
1490+
LocalVariable::kNoKernelOffset);
14901491
} else {
14911492
// If the type parameter is a parameter to this or an enclosing function,
14921493
// we can read it directly from the function type arguments vector later.
@@ -1608,9 +1609,12 @@ void ScopeBuilder::AddVariableDeclarationParameter(
16081609
intptr_t pos,
16091610
ParameterTypeCheckMode type_check_mode,
16101611
const ProcedureAttributesMetadata& attrs) {
1611-
intptr_t kernel_offset = helper_.ReaderOffset(); // no tag.
1612+
// Convert kernel offset of variable declaration to absolute.
1613+
const intptr_t kernel_offset =
1614+
helper_.data_program_offset_ + helper_.ReaderOffset();
1615+
// MetadataHelper expects relative offsets and adjusts them internally
16121616
const InferredTypeMetadata parameter_type =
1613-
inferred_type_metadata_helper_.GetInferredType(kernel_offset);
1617+
inferred_type_metadata_helper_.GetInferredType(helper_.ReaderOffset());
16141618
VariableDeclarationHelper helper(&helper_);
16151619
helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
16161620
String& name = H.DartSymbolObfuscate(helper.name_index_);
@@ -1619,8 +1623,9 @@ void ScopeBuilder::AddVariableDeclarationParameter(
16191623
helper.SetJustRead(VariableDeclarationHelper::kType);
16201624
helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
16211625

1622-
LocalVariable* variable = MakeVariable(helper.position_, helper.position_,
1623-
name, type, &parameter_type);
1626+
LocalVariable* variable =
1627+
MakeVariable(helper.position_, helper.position_, name, type,
1628+
kernel_offset, &parameter_type);
16241629
if (helper.IsFinal()) {
16251630
variable->set_is_final();
16261631
}
@@ -1681,8 +1686,7 @@ void ScopeBuilder::AddVariableDeclarationParameter(
16811686
}
16821687

16831688
scope_->InsertParameterAt(pos, variable);
1684-
result_->locals.Insert(helper_.data_program_offset_ + kernel_offset,
1685-
variable);
1689+
result_->locals.Insert(kernel_offset, variable);
16861690

16871691
// The default value may contain 'let' bindings for which the constant
16881692
// evaluator needs scope bindings.
@@ -1697,6 +1701,7 @@ LocalVariable* ScopeBuilder::MakeVariable(
16971701
TokenPosition token_pos,
16981702
const String& name,
16991703
const AbstractType& type,
1704+
intptr_t kernel_offset,
17001705
const InferredTypeMetadata* param_type_md /* = NULL */) {
17011706
CompileType* param_type = nullptr;
17021707
const Object* param_value = nullptr;
@@ -1707,7 +1712,7 @@ LocalVariable* ScopeBuilder::MakeVariable(
17071712
}
17081713
}
17091714
return new (Z) LocalVariable(declaration_pos, token_pos, name, type,
1710-
param_type, param_value);
1715+
kernel_offset, param_type, param_value);
17111716
}
17121717

17131718
void ScopeBuilder::AddExceptionVariable(
@@ -1823,7 +1828,7 @@ void ScopeBuilder::VisitVariableGet(intptr_t declaration_binary_offset) {
18231828
LocalVariable* ScopeBuilder::LookupVariable(
18241829
intptr_t declaration_binary_offset) {
18251830
LocalVariable* variable = result_->locals.Lookup(declaration_binary_offset);
1826-
if (variable == NULL) {
1831+
if (variable == nullptr) {
18271832
// We have not seen a declaration of the variable, so it must be the
18281833
// case that we are compiling a nested function and the variable is
18291834
// declared in an outer scope. In that case, look it up in the scope by
@@ -1834,11 +1839,13 @@ LocalVariable* ScopeBuilder::LookupVariable(
18341839
parsed_function_->function());
18351840

18361841
const String& name = H.DartSymbolObfuscate(var_name);
1837-
variable = current_function_scope_->parent()->LookupVariable(name, true);
1838-
ASSERT(variable != NULL);
1842+
variable = current_function_scope_->parent()->LookupVariable(
1843+
name, declaration_binary_offset, true);
1844+
ASSERT(variable != nullptr);
18391845
result_->locals.Insert(declaration_binary_offset, variable);
18401846
}
18411847

1848+
ASSERT(variable->owner() != nullptr);
18421849
if (variable->owner()->function_level() < scope_->function_level()) {
18431850
// We call `LocalScope->CaptureVariable(variable)` in two scenarios for two
18441851
// different reasons:
@@ -1885,8 +1892,8 @@ void ScopeBuilder::HandleLoadReceiver() {
18851892
current_function_scope_->parent() != nullptr) {
18861893
// Lazily populate receiver variable using the parent function scope.
18871894
parsed_function_->set_receiver_var(
1888-
current_function_scope_->parent()->LookupVariable(Symbols::This(),
1889-
true));
1895+
current_function_scope_->parent()->LookupVariable(
1896+
Symbols::This(), LocalVariable::kNoKernelOffset, true));
18901897
}
18911898

18921899
if ((current_function_scope_->parent() != nullptr) ||
@@ -1899,13 +1906,14 @@ void ScopeBuilder::HandleLoadReceiver() {
18991906
}
19001907

19011908
void ScopeBuilder::HandleSpecialLoad(LocalVariable** variable,
1902-
const String& symbol) {
1909+
const String& symbol,
1910+
intptr_t kernel_offset) {
19031911
if (current_function_scope_->parent() != NULL) {
19041912
// We are building the scope tree of a closure function and saw [node]. We
19051913
// lazily populate the variable using the parent function scope.
19061914
if (*variable == NULL) {
1907-
*variable =
1908-
current_function_scope_->parent()->LookupVariable(symbol, true);
1915+
*variable = current_function_scope_->parent()->LookupVariable(
1916+
symbol, kernel_offset, true);
19091917
ASSERT(*variable != NULL);
19101918
}
19111919
}
@@ -1919,14 +1927,5 @@ void ScopeBuilder::HandleSpecialLoad(LocalVariable** variable,
19191927
}
19201928
}
19211929

1922-
void ScopeBuilder::LookupCapturedVariableByName(LocalVariable** variable,
1923-
const String& name) {
1924-
if (*variable == NULL) {
1925-
*variable = scope_->LookupVariable(name, true);
1926-
ASSERT(*variable != NULL);
1927-
scope_->CaptureVariable(*variable);
1928-
}
1929-
}
1930-
19311930
} // namespace kernel
19321931
} // namespace dart

runtime/vm/compiler/frontend/scope_builder.h

+10-8
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ class ScopeBuilder {
9898
ParameterTypeCheckMode type_check_mode,
9999
const ProcedureAttributesMetadata& attrs);
100100

101-
LocalVariable* MakeVariable(TokenPosition declaration_pos,
102-
TokenPosition token_pos,
103-
const String& name,
104-
const AbstractType& type,
105-
const InferredTypeMetadata* param_type_md = NULL);
101+
LocalVariable* MakeVariable(
102+
TokenPosition declaration_pos,
103+
TokenPosition token_pos,
104+
const String& name,
105+
const AbstractType& type,
106+
intptr_t kernel_offset = LocalVariable::kNoKernelOffset,
107+
const InferredTypeMetadata* param_type_md = NULL);
106108

107109
void AddExceptionVariable(GrowableArray<LocalVariable*>* variables,
108110
const char* prefix,
@@ -130,9 +132,9 @@ class ScopeBuilder {
130132
const String& GenerateName(const char* prefix, intptr_t suffix);
131133

132134
void HandleLoadReceiver();
133-
void HandleSpecialLoad(LocalVariable** variable, const String& symbol);
134-
void LookupCapturedVariableByName(LocalVariable** variable,
135-
const String& name);
135+
void HandleSpecialLoad(LocalVariable** variable,
136+
const String& symbol,
137+
intptr_t kernel_offset);
136138

137139
struct DepthState {
138140
explicit DepthState(intptr_t function)

0 commit comments

Comments
 (0)