mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
9be13288b0
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 https://github.com/dart-lang/sdk/issues/51091 Issue https://github.com/dart-lang/sdk/issues/49755 Change-Id: I0263769cb31f3f8d9652f5d6534800510ac882fb Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/279650 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
117 lines
4.3 KiB
C++
117 lines
4.3 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/scopes.h"
|
|
#include "platform/assert.h"
|
|
#include "vm/unit_test.h"
|
|
|
|
namespace dart {
|
|
|
|
ISOLATE_UNIT_TEST_CASE(LocalScope) {
|
|
// Allocate a couple of local variables first.
|
|
const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
|
|
const String& a = String::ZoneHandle(Symbols::New(thread, "a"));
|
|
LocalVariable* var_a = new LocalVariable(
|
|
TokenPosition::kNoSource, TokenPosition::kNoSource, a, dynamic_type);
|
|
LocalVariable* inner_var_a = new LocalVariable(
|
|
TokenPosition::kNoSource, TokenPosition::kNoSource, a, dynamic_type);
|
|
const String& b = String::ZoneHandle(Symbols::New(thread, "b"));
|
|
LocalVariable* var_b = new LocalVariable(
|
|
TokenPosition::kNoSource, TokenPosition::kNoSource, b, dynamic_type);
|
|
const String& c = String::ZoneHandle(Symbols::New(thread, "c"));
|
|
LocalVariable* var_c = new LocalVariable(
|
|
TokenPosition::kNoSource, TokenPosition::kNoSource, c, dynamic_type);
|
|
|
|
LocalScope* outer_scope = new LocalScope(NULL, 0, 0);
|
|
LocalScope* inner_scope1 = new LocalScope(outer_scope, 0, 0);
|
|
LocalScope* inner_scope2 = new LocalScope(outer_scope, 0, 0);
|
|
|
|
EXPECT(outer_scope->parent() == NULL);
|
|
EXPECT_EQ(outer_scope, inner_scope1->parent());
|
|
EXPECT_EQ(outer_scope, inner_scope2->parent());
|
|
EXPECT_EQ(inner_scope2, outer_scope->child());
|
|
EXPECT_EQ(inner_scope1, inner_scope2->sibling());
|
|
EXPECT(inner_scope1->child() == NULL);
|
|
EXPECT(inner_scope2->child() == NULL);
|
|
|
|
// Populate the local scopes as follows:
|
|
// { // outer_scope
|
|
// var a;
|
|
// { // inner_scope1
|
|
// var b;
|
|
// }
|
|
// L: { // inner_scope2
|
|
// var c;
|
|
// }
|
|
// }
|
|
EXPECT(outer_scope->AddVariable(var_a));
|
|
EXPECT(inner_scope1->AddVariable(var_b));
|
|
EXPECT(inner_scope2->AddVariable(var_c));
|
|
EXPECT(!outer_scope->AddVariable(var_a));
|
|
|
|
// Check the simple layout above.
|
|
EXPECT_EQ(var_a, outer_scope->LocalLookupVariable(
|
|
a, LocalVariable::kNoKernelOffset));
|
|
EXPECT_EQ(var_a, inner_scope1->LookupVariable(
|
|
a, LocalVariable::kNoKernelOffset, true));
|
|
EXPECT(outer_scope->LocalLookupVariable(b, LocalVariable::kNoKernelOffset) ==
|
|
NULL);
|
|
EXPECT(inner_scope1->LocalLookupVariable(c, LocalVariable::kNoKernelOffset) ==
|
|
NULL);
|
|
|
|
// Modify the local scopes to contain shadowing:
|
|
// { // outer_scope
|
|
// var a;
|
|
// { // inner_scope1
|
|
// var b;
|
|
// var a; // inner_var_a
|
|
// }
|
|
// { // inner_scope2
|
|
// var c;
|
|
// L: ...
|
|
// }
|
|
// }
|
|
EXPECT(inner_scope1->AddVariable(inner_var_a));
|
|
EXPECT_EQ(inner_var_a, inner_scope1->LookupVariable(
|
|
a, LocalVariable::kNoKernelOffset, true));
|
|
EXPECT(inner_scope1->LookupVariable(a, LocalVariable::kNoKernelOffset,
|
|
true) != var_a);
|
|
|
|
// Modify the local scopes with access of an outer scope variable:
|
|
// { // outer_scope
|
|
// var a;
|
|
// { // inner_scope1
|
|
// var b;
|
|
// var a; // inner_var_a
|
|
// }
|
|
// { // inner_scope2
|
|
// var c = a;
|
|
// L: ...
|
|
// }
|
|
// }
|
|
EXPECT(inner_scope2->LocalLookupVariable(a, LocalVariable::kNoKernelOffset) ==
|
|
NULL);
|
|
EXPECT(inner_scope2->AddVariable(var_a));
|
|
EXPECT_EQ(var_a, inner_scope2->LocalLookupVariable(
|
|
a, LocalVariable::kNoKernelOffset));
|
|
|
|
EXPECT_EQ(1, outer_scope->num_variables());
|
|
EXPECT_EQ(2, inner_scope1->num_variables());
|
|
EXPECT_EQ(2, inner_scope2->num_variables());
|
|
|
|
// Cannot depend on the order, but we should find the variables.
|
|
EXPECT(outer_scope->VariableAt(0) == var_a);
|
|
EXPECT((inner_scope1->VariableAt(0) == inner_var_a) ||
|
|
(inner_scope1->VariableAt(1) == inner_var_a));
|
|
EXPECT((inner_scope1->VariableAt(0) == var_b) ||
|
|
(inner_scope1->VariableAt(1) == var_b));
|
|
EXPECT((inner_scope2->VariableAt(0) == var_a) ||
|
|
(inner_scope2->VariableAt(1) == var_a) ||
|
|
(inner_scope2->VariableAt(2) == var_a));
|
|
EXPECT((inner_scope2->VariableAt(0) == var_c) ||
|
|
(inner_scope2->VariableAt(1) == var_c) ||
|
|
(inner_scope2->VariableAt(2) == var_c));
|
|
}
|
|
|
|
} // namespace dart
|