[cfe] Make VariableBase.context independent from VariableBase.parent

Previously the getter VariableBase.context was redirecting to
VariableBase.parent, effectively requiring a change of the ownership
over the variable. This CL makes VariableBase.context a field of
VariableBase, allowing for the previously existing ownership structure
of the AST tree nodes.

The change allows to avoid workarounds for the existing
ownership-restoring logic, such as the assignments to the `parent`
pointer made in the constructors of the AST nodes and their
`transformChildren` and `transformOrRemoveChildren` methods.

Part of https://github.com/dart-lang/sdk/issues/61572

Change-Id: I307c9d2b23c8201f8d7d2a100acf9fb8f3af2572
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/494441
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Chloe Stefantsova
2026-05-12 00:08:47 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 3d339f3955
commit 09a156bb2d
9 changed files with 197 additions and 50 deletions
@@ -292,11 +292,11 @@ class FormalParameterBuilder extends NamedBuilderImpl
)..fileOffset = fileOffset;
}
}
return _variable!.asExpressionVariable;
return _variable!.asVariableDeclaration;
}
@override
VariableDeclaration get variable => _variable!.asExpressionVariable;
VariableDeclaration get variable => _variable!.asVariableDeclaration;
@override
void onInferredType(DartType type) {
@@ -592,7 +592,7 @@ class CatchParameterBuilder extends NamedBuilderImpl
String get fullNameForErrors => name;
@override
VariableDeclaration get variable => _variable!.asExpressionVariable;
VariableDeclaration get variable => _variable!.asVariableDeclaration;
@override
VariableDeclaration build(SourceLibraryBuilder library) {
@@ -630,7 +630,7 @@ class CatchParameterBuilder extends NamedBuilderImpl
)..fileOffset = fileOffset;
}
}
return _variable!.asExpressionVariable;
return _variable!.asVariableDeclaration;
}
@override
@@ -3413,7 +3413,7 @@ class BodyBuilderImpl extends StackListenerImpl
isImplicitlyTyped: currentLocalVariableType == null,
);
variableInitialization = new VariableInitialization(
variable: internalVariable.asExpressionVariable,
variable: internalVariable.asVariableDeclaration,
initializer: initializer,
hasDeclaredInitializer: initializer != null,
);
+14 -7
View File
@@ -1165,13 +1165,13 @@ class InternalPositionalParameter extends TreeNode
});
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
List<VariableContext>? get capturedContexts {
throw new UnsupportedError("${this.runtimeType}.capturedContexts");
}
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
void set capturedContexts(List<VariableContext>? value) {
throw new UnsupportedError("${this.runtimeType}.capturedContexts=");
}
@@ -1268,13 +1268,13 @@ class InternalNamedParameter extends TreeNode
});
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
List<VariableContext>? get capturedContexts {
throw new UnsupportedError("${this.runtimeType}.capturedContexts");
}
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
void set capturedContexts(List<VariableContext>? value) {
throw new UnsupportedError("${this.runtimeType}.capturedContexts=");
}
@@ -1718,6 +1718,7 @@ mixin DelegatingVariableMixin on InternalVariableMixin
}
@override
// Coverage-ignore(suite): Not run.
R accept1<R, A>(StatementVisitor1<R, A> v, A arg) {
return astVariable.accept1(v, arg);
}
@@ -1729,8 +1730,14 @@ mixin DelegatingVariableMixin on InternalVariableMixin
astVariable.cosmeticName = value;
}
VariableContext get context {
throw new UnsupportedError("${this.runtimeType}");
@override
// Coverage-ignore(suite): Not run.
VariableContext get context => astVariable.context;
@override
// Coverage-ignore(suite): Not run.
void set context(VariableContext value) {
astVariable.context = value;
}
@override
@@ -1937,7 +1944,7 @@ mixin InternalVariableMixin on TreeNode implements InternalVariable {
String? lateName;
@override
VariableDeclaration get asExpressionVariable => this as VariableDeclaration;
VariableDeclaration get asVariableDeclaration => this as VariableDeclaration;
}
/// Front end specific implementation of [LoadLibrary].
@@ -13242,6 +13242,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
exceptionCatchVariable,
captureKind: _captureKindForVariable(exceptionCatchVariable),
);
node.exception = exceptionCatchVariable;
}
if (node.stackTrace case CatchVariable stackTraceCatchVariable?) {
// TODO(62401): Remove the casts when the flow analysis uses
@@ -13253,6 +13254,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
stackTraceCatchVariable,
captureKind: _captureKindForVariable(stackTraceCatchVariable),
);
node.stackTrace = stackTraceCatchVariable;
}
}
StatementInferenceResult bodyResult = inferStatement(node.body);
+69 -25
View File
@@ -1593,13 +1593,13 @@ class VariableStatement extends Statement
}
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
List<VariableContext>? get capturedContexts {
throw new UnsupportedError("${this.runtimeType}.capturedContexts");
}
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
void set capturedContexts(List<VariableContext>? value) {
throw new UnsupportedError("${this.runtimeType}.capturedContexts=");
}
@@ -1890,28 +1890,33 @@ class VariableStatement extends Statement
@override
VariableDeclaration? get variableInitialization {
throw new UnsupportedError("${this.runtimeType}");
throw new UnsupportedError("${this.runtimeType}.variableInitialization");
}
@override
void set variableInitialization(VariableDeclaration? value) {
throw new UnsupportedError("${this.runtimeType}");
throw new UnsupportedError("${this.runtimeType}.variableInitialization=");
}
@override
VariableContext get context {
throw new UnsupportedError("${this.runtimeType}");
throw new UnsupportedError("${this.runtimeType}.context");
}
@override
VariableDeclaration get asExpressionVariable => this;
void set context(VariableContext value) {
throw new UnsupportedError("${this.runtimeType}.context=");
}
@override
VariableDeclaration get asVariableDeclaration => this;
@override
VariableDeclaration get variable => this;
@override
void set variable(VariableDeclaration value) {
throw new UnsupportedError("${this.runtimeType}");
throw new UnsupportedError("${this.runtimeType}.variable=");
}
@override
@@ -2274,78 +2279,117 @@ class VariableInitialization extends Statement implements VariableDeclaration {
}
@override
VariableContext get context => variable.context;
@override
VariableDeclaration get asExpressionVariable => variable;
VariableDeclaration get asVariableDeclaration => variable;
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasHasDeclaredInitializer => throw UnimplementedError();
VariableContext get context {
throw UnsupportedError("${runtimeType}.context");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsConst => throw UnimplementedError();
void set context(VariableContext value) {
throw UnsupportedError("${runtimeType}.context=");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsCovariantByClass => throw UnimplementedError();
bool get hasHasDeclaredInitializer {
throw UnsupportedError("${runtimeType}.hasHasDeclaredInitializer");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsCovariantByDeclaration => throw UnimplementedError();
bool get hasIsConst {
throw new UnsupportedError("${runtimeType}.hasIsConst");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsErroneouslyInitialized => throw UnimplementedError();
bool get hasIsCovariantByClass {
throw new UnsupportedError("${runtimeType}.hasIsCovariantByClass");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsFinal => throw UnimplementedError();
bool get hasIsCovariantByDeclaration {
throw new UnsupportedError("${runtimeType}.hasIsCovariantByDeclaration");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsHoisted => throw UnimplementedError();
bool get hasIsErroneouslyInitialized {
throw new UnsupportedError("${runtimeType}.hasIsErroneouslyInitialized");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsInitializingFormal => throw UnimplementedError();
bool get hasIsFinal {
throw new UnsupportedError("${runtimeType}.hasIsFinal");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsLate => throw UnimplementedError();
bool get hasIsHoisted {
throw new UnsupportedError("${runtimeType}.hasIsHoisted");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsLowered => throw UnimplementedError();
bool get hasIsInitializingFormal {
throw new UnsupportedError("${runtimeType}.hasIsInitializingFormal");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsRequired => throw UnimplementedError();
bool get hasIsLate {
throw new UnsupportedError("${runtimeType}.hasIsLate");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsSuperInitializingFormal => throw UnimplementedError();
bool get hasIsLowered {
throw new UnsupportedError("${runtimeType}.hasIsLowered");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsSynthesized => throw UnimplementedError();
bool get hasIsRequired {
throw new UnsupportedError("${runtimeType}.hasIsRequired");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsWildcard => throw UnimplementedError();
bool get hasIsSuperInitializingFormal {
throw new UnsupportedError("${runtimeType}.hasIsSuperInitializingFormal");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsSynthesized {
throw new UnsupportedError("${runtimeType}.hasIsSynthesized");
}
@override
// TODO(62620): Remove the method when the [VariableInitialization] stops
// implementing [VariableDeclaration].
bool get hasIsWildcard {
throw new UnsupportedError("${runtimeType}.hasIsWildcard");
}
}
+3
View File
@@ -2446,6 +2446,9 @@ class TypeVariable extends VariableBase {
@override
String? cosmeticName;
@override
late VariableContext context;
/// Function type parameter this [TypeVariable] is associated with.
final TypeParameter parameter;
+27 -8
View File
@@ -6,7 +6,7 @@ part of '../../ast.dart';
/// Generalized notion of a variable.
sealed class VariableBase extends TreeNode implements Annotatable {
VariableContext get context => parent as VariableContext;
abstract VariableContext context;
/// The cosmetic name of the variable from the source code, if exists.
String? get cosmeticName;
@@ -30,6 +30,7 @@ abstract interface class IVariable implements TreeNode {
abstract String? cosmeticName;
abstract VariableDeclaration? variableInitialization;
abstract Expression? initializer;
abstract VariableContext context;
abstract bool isFinal;
abstract bool isConst;
abstract bool isLate;
@@ -68,7 +69,7 @@ abstract interface class IVariable implements TreeNode {
bool get hasIsWildcard;
bool get hasIsSuperInitializingFormal;
bool get hasIsErroneouslyInitialized;
VariableDeclaration get asExpressionVariable;
VariableDeclaration get asVariableDeclaration;
}
/// The root of the sealed hierarchy of non-type variables.
@@ -184,7 +185,7 @@ sealed class VariableDeclaration extends VariableBase
bool get isAssignable;
@override
VariableDeclaration get asExpressionVariable => this;
VariableDeclaration get asVariableDeclaration => this;
abstract String? name;
}
@@ -206,6 +207,9 @@ class LocalVariable extends VariableDeclaration {
@override
List<Expression> annotations = const <Expression>[];
@override
late VariableContext context;
LocalVariable({
this.cosmeticName,
required DartType? type,
@@ -512,6 +516,9 @@ class CatchVariable extends VariableDeclaration {
@override
List<Expression> annotations = const <Expression>[];
@override
late VariableContext context;
CatchVariable({
required String name,
required DartType? type,
@@ -1012,6 +1019,9 @@ class PositionalParameter extends FunctionParameter {
@override
List<Expression> annotations = const <Expression>[];
@override
late VariableContext context;
PositionalParameter({
this.cosmeticName,
required this.type,
@@ -1028,13 +1038,13 @@ class PositionalParameter extends FunctionParameter {
});
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
List<VariableContext>? get capturedContexts {
throw new UnsupportedError("${this.runtimeType}.capturedContexts");
}
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
void set capturedContexts(List<VariableContext>? value) {
throw new UnsupportedError("${this.runtimeType}.capturedContexts=");
}
@@ -1156,6 +1166,9 @@ class NamedParameter extends FunctionParameter {
@override
List<Expression> annotations = const <Expression>[];
@override
late VariableContext context;
NamedParameter({
required this.parameterName,
required this.type,
@@ -1172,13 +1185,13 @@ class NamedParameter extends FunctionParameter {
});
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
List<VariableContext>? get capturedContexts {
throw new UnsupportedError("${this.runtimeType}.capturedContexts");
}
@override
// TODO(62620): Conforming to [VariableInitialization] interface. Remove this.
// TODO(62620): Conforming to [VariableDeclaration] interface. Remove this.
void set capturedContexts(List<VariableContext>? value) {
throw new UnsupportedError("${this.runtimeType}.capturedContexts=");
}
@@ -1303,6 +1316,9 @@ class ThisVariable extends VariableDeclaration {
@override
List<Expression> annotations = const <Expression>[];
@override
late VariableContext context;
ThisVariable({required this.type}) : super.empty();
// TODO(cstefantsova): Consider a throwing implementation instead.
@@ -1578,6 +1594,9 @@ class SyntheticVariable extends VariableDeclaration {
@override
List<Expression> annotations = const <Expression>[];
@override
late VariableContext context;
SyntheticVariable({this.cosmeticName, required this.type}) : super.empty();
// TODO(cstefantsova): Consider a throwing implementation instead.
@@ -1854,7 +1873,7 @@ class VariableContext extends TreeNode {
VariableContext({required this.captureKind, required this.variables});
void addVariable(VariableBase variable) {
variable.parent = this;
variable.context = this;
variables.add(variable);
}
+77
View File
@@ -6060,6 +6060,9 @@ class EquivalenceStrategy {
if (!checkLocalVariable_annotations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkLocalVariable_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkLocalVariable_binaryOffsetNoTag(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -6095,6 +6098,9 @@ class EquivalenceStrategy {
if (!checkCatchVariable_annotations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkCatchVariable_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkCatchVariable_binaryOffsetNoTag(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -6130,6 +6136,9 @@ class EquivalenceStrategy {
if (!checkPositionalParameter_annotations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkPositionalParameter_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkPositionalParameter_binaryOffsetNoTag(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -6168,6 +6177,9 @@ class EquivalenceStrategy {
if (!checkNamedParameter_annotations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkNamedParameter_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkNamedParameter_binaryOffsetNoTag(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -6203,6 +6215,9 @@ class EquivalenceStrategy {
if (!checkThisVariable_annotations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkThisVariable_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkThisVariable_binaryOffsetNoTag(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -6241,6 +6256,9 @@ class EquivalenceStrategy {
if (!checkSyntheticVariable_annotations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkSyntheticVariable_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkSyntheticVariable_binaryOffsetNoTag(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -6270,6 +6288,9 @@ class EquivalenceStrategy {
if (!checkTypeVariable_cosmeticName(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkTypeVariable_context(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkTypeVariable_parameter(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
@@ -13513,6 +13534,14 @@ class EquivalenceStrategy {
);
}
bool checkLocalVariable_context(
EquivalenceVisitor visitor,
LocalVariable node,
LocalVariable other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkLocalVariable_binaryOffsetNoTag(
EquivalenceVisitor visitor,
LocalVariable node,
@@ -13618,6 +13647,14 @@ class EquivalenceStrategy {
);
}
bool checkCatchVariable_context(
EquivalenceVisitor visitor,
CatchVariable node,
CatchVariable other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkCatchVariable_binaryOffsetNoTag(
EquivalenceVisitor visitor,
CatchVariable node,
@@ -13691,6 +13728,14 @@ class EquivalenceStrategy {
);
}
bool checkPositionalParameter_context(
EquivalenceVisitor visitor,
PositionalParameter node,
PositionalParameter other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkPositionalParameter_binaryOffsetNoTag(
EquivalenceVisitor visitor,
PositionalParameter node,
@@ -13800,6 +13845,14 @@ class EquivalenceStrategy {
);
}
bool checkNamedParameter_context(
EquivalenceVisitor visitor,
NamedParameter node,
NamedParameter other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkNamedParameter_binaryOffsetNoTag(
EquivalenceVisitor visitor,
NamedParameter node,
@@ -13869,6 +13922,14 @@ class EquivalenceStrategy {
);
}
bool checkThisVariable_context(
EquivalenceVisitor visitor,
ThisVariable node,
ThisVariable other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkThisVariable_binaryOffsetNoTag(
EquivalenceVisitor visitor,
ThisVariable node,
@@ -13954,6 +14015,14 @@ class EquivalenceStrategy {
);
}
bool checkSyntheticVariable_context(
EquivalenceVisitor visitor,
SyntheticVariable node,
SyntheticVariable other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkSyntheticVariable_binaryOffsetNoTag(
EquivalenceVisitor visitor,
SyntheticVariable node,
@@ -14006,6 +14075,14 @@ class EquivalenceStrategy {
);
}
bool checkTypeVariable_context(
EquivalenceVisitor visitor,
TypeVariable node,
TypeVariable other,
) {
return visitor.checkNodes(node.context, other.context, 'context');
}
bool checkTypeVariable_parameter(
EquivalenceVisitor visitor,
TypeVariable node,
-5
View File
@@ -1180,11 +1180,6 @@ class VerifyingVisitor extends RecursiveResultVisitor<void> {
exitTreeNode(node);
}
@override
void visitLocalVariable(LocalVariable node) {
declareVariable(node);
}
@override
void visitVariableGet(VariableGet node) {
// TODO(cstefantsova): Support new variable model.