[cfe] Use VariableInitialization in ForStatement and similar nodes

This change is similar to
https://github.com/dart-lang/sdk/commit/c97e2554ee3b21b0b0146ca41be969dd8531986d,
where ExpressionVariable was used in VariableGet and VariableSet.

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

Change-Id: Id9fa5302adcf8c773cec8478a31948b54c8393b6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/466720
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Chloe Stefantsova
2025-12-08 04:56:51 -08:00
committed by Commit Queue
parent b976f6c69b
commit 95df731257
22 changed files with 307 additions and 141 deletions
+12 -12
View File
@@ -3751,7 +3751,7 @@ class BodyBuilderImpl extends StackListenerImpl
}
}
List<VariableDeclaration>? _buildForLoopVariableDeclarations(
List<VariableInitialization>? _buildForLoopVariableDeclarations(
variableOrExpression,
) {
// TODO(ahe): This can be simplified now that we have the events
@@ -3759,40 +3759,40 @@ class BodyBuilderImpl extends StackListenerImpl
if (variableOrExpression is Generator) {
variableOrExpression = variableOrExpression.buildForEffect();
}
if (variableOrExpression is VariableDeclaration) {
if (variableOrExpression is VariableInitialization) {
// Late for loop variables are not supported. An error has already been
// reported by the parser.
variableOrExpression.isLate = false;
return <VariableDeclaration>[variableOrExpression];
return <VariableInitialization>[variableOrExpression];
} else if (variableOrExpression is Expression) {
VariableDeclaration variable = new VariableDeclarationImpl.forEffect(
variableOrExpression,
);
return <VariableDeclaration>[variable];
return <VariableInitialization>[variable];
} else if (variableOrExpression is ExpressionStatement) {
// Coverage-ignore-block(suite): Not run.
VariableDeclaration variable = new VariableDeclarationImpl.forEffect(
variableOrExpression.expression,
);
return <VariableDeclaration>[variable];
return <VariableInitialization>[variable];
} else if (forest.isVariablesDeclaration(variableOrExpression)) {
return forest.variablesDeclarationExtractDeclarations(
variableOrExpression,
);
} else if (variableOrExpression is List<Object>) {
// Coverage-ignore-block(suite): Not run.
List<VariableDeclaration> variables = <VariableDeclaration>[];
List<VariableInitialization> variables = <VariableInitialization>[];
for (Object v in variableOrExpression) {
variables.addAll(_buildForLoopVariableDeclarations(v)!);
}
return variables;
} else if (variableOrExpression is PatternVariableDeclaration) {
// Coverage-ignore-block(suite): Not run.
return <VariableDeclaration>[];
return <VariableInitialization>[];
} else if (variableOrExpression is ParserRecovery) {
return <VariableDeclaration>[];
return <VariableInitialization>[];
} else if (variableOrExpression == null) {
return <VariableDeclaration>[];
return <VariableInitialization>[];
}
return null;
}
@@ -3991,7 +3991,7 @@ class BodyBuilderImpl extends StackListenerImpl
.popNode();
Object? variableOrExpression = pop();
List<VariableDeclaration>? variables;
List<VariableInitialization>? variables;
List<VariableDeclaration>? intermediateVariables;
if (variableOrExpression is PatternVariableDeclaration) {
variables = pop() as List<VariableDeclaration>; // Internal variables.
@@ -4015,7 +4015,7 @@ class BodyBuilderImpl extends StackListenerImpl
offsetForToken(forToken),
patternVariableDeclaration: variableOrExpression,
intermediateVariables: intermediateVariables!,
variables: variables,
variableInitializations: variables,
condition: condition,
updates: updates,
body: entry,
@@ -4110,7 +4110,7 @@ class BodyBuilderImpl extends StackListenerImpl
.deferNode();
Object? variableOrExpression = pop();
List<VariableDeclaration>? variables;
List<VariableInitialization>? variables;
List<VariableDeclaration>? intermediateVariables;
if (variableOrExpression is PatternVariableDeclaration) {
variables = pop() as List<VariableDeclaration>;
+66 -33
View File
@@ -270,8 +270,13 @@ class IfElement extends ControlFlowElement with ControlFlowElementMixin {
class ForElement extends ControlFlowElement
with ControlFlowElementMixin
implements ForElementBase {
// May be empty, but not null.
@override
final List<VariableDeclaration> variables; // May be empty, but not null.
final List<VariableInitialization> variableInitializations;
@override
// Coverage-ignore(suite): Not run.
List<VariableDeclaration> get variables => variableInitializations.cast();
@override
Expression? condition; // May be null.
@@ -282,8 +287,13 @@ class ForElement extends ControlFlowElement
@override
Expression body;
ForElement(this.variables, this.condition, this.updates, this.body) {
setParents(variables, this);
ForElement(
this.variableInitializations,
this.condition,
this.updates,
this.body,
) {
setParents(variableInitializations, this);
condition?.parent = this;
setParents(updates, this);
body.parent = this;
@@ -292,7 +302,7 @@ class ForElement extends ControlFlowElement
@override
// Coverage-ignore(suite): Not run.
void visitChildren(Visitor v) {
visitList(variables, v);
visitList(variableInitializations, v);
condition?.accept(v);
visitList(updates, v);
body.accept(v);
@@ -301,7 +311,7 @@ class ForElement extends ControlFlowElement
@override
// Coverage-ignore(suite): Not run.
void transformChildren(Transformer v) {
v.transformList(variables, this);
v.transformList(variableInitializations, this);
if (condition != null) {
condition = v.transform(condition!);
condition?.parent = this;
@@ -314,7 +324,7 @@ class ForElement extends ControlFlowElement
@override
// Coverage-ignore(suite): Not run.
void transformOrRemoveChildren(RemovingTransformer v) {
v.transformVariableDeclarationList(variables, this);
v.transformVariableInitializationList(variableInitializations, this);
if (condition != null) {
condition = v.transformOrRemoveExpression(condition!);
condition?.parent = this;
@@ -336,7 +346,7 @@ class ForElement extends ControlFlowElement
}
if (bodyEntry == null) return null;
ForMapEntry result = new ForMapEntry(
variables,
variableInitializations,
condition,
updates,
bodyEntry,
@@ -354,12 +364,12 @@ class ForElement extends ControlFlowElement
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < variableInitializations.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
variableInitializations[index],
includeModifiersAndType: index == 0,
);
}
@@ -593,6 +603,8 @@ class IfCaseElement extends ControlFlowElementImpl
}
abstract interface class ForElementBase implements AuxiliaryExpression {
List<VariableInitialization> get variableInitializations;
List<VariableDeclaration> get variables;
abstract Expression? condition;
@@ -608,8 +620,13 @@ class PatternForElement extends ControlFlowElementImpl
PatternVariableDeclaration patternVariableDeclaration;
List<VariableDeclaration> intermediateVariables;
// May be empty, but not null.
@override
final List<VariableDeclaration> variables; // May be empty, but not null.
final List<VariableInitialization> variableInitializations;
@override
// Coverage-ignore(suite): Not run.
List<VariableDeclaration> get variables => variableInitializations.cast();
@override
Expression? condition; // May be null.
@@ -623,11 +640,11 @@ class PatternForElement extends ControlFlowElementImpl
PatternForElement({
required this.patternVariableDeclaration,
required this.intermediateVariables,
required this.variables,
required List<VariableInitialization> variables,
required this.condition,
required this.updates,
required this.body,
});
}) : variableInitializations = variables;
@override
ExpressionInferenceResult acceptInference(
@@ -642,12 +659,12 @@ class PatternForElement extends ControlFlowElementImpl
void toTextInternal(AstPrinter printer) {
patternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < variableInitializations.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
variableInitializations[index],
includeModifiersAndType: index == 0,
);
}
@@ -893,6 +910,8 @@ class IfMapEntry extends TreeNode
}
abstract interface class ForMapEntryBase implements TreeNode, MapLiteralEntry {
List<VariableInitialization> get variableInitializations;
List<VariableDeclaration> get variables;
abstract Expression? condition;
@@ -906,8 +925,13 @@ abstract interface class ForMapEntryBase implements TreeNode, MapLiteralEntry {
class ForMapEntry extends TreeNode
with ControlFlowMapEntryMixin
implements ForMapEntryBase, ControlFlowMapEntry {
// May be empty, but not null.
@override
final List<VariableDeclaration> variables; // May be empty, but not null.
final List<VariableInitialization> variableInitializations;
@override
// Coverage-ignore(suite): Not run.
List<VariableDeclaration> get variables => variableInitializations.cast();
@override
Expression? condition; // May be null.
@@ -918,8 +942,13 @@ class ForMapEntry extends TreeNode
@override
MapLiteralEntry body;
ForMapEntry(this.variables, this.condition, this.updates, this.body) {
setParents(variables, this);
ForMapEntry(
this.variableInitializations,
this.condition,
this.updates,
this.body,
) {
setParents(variableInitializations, this);
condition?.parent = this;
setParents(updates, this);
body.parent = this;
@@ -928,7 +957,7 @@ class ForMapEntry extends TreeNode
@override
// Coverage-ignore(suite): Not run.
void visitChildren(Visitor v) {
visitList(variables, v);
visitList(variableInitializations, v);
condition?.accept(v);
visitList(updates, v);
body.accept(v);
@@ -937,7 +966,7 @@ class ForMapEntry extends TreeNode
@override
// Coverage-ignore(suite): Not run.
void transformChildren(Transformer v) {
v.transformList(variables, this);
v.transformList(variableInitializations, this);
if (condition != null) {
condition = v.transform(condition!);
condition?.parent = this;
@@ -950,7 +979,7 @@ class ForMapEntry extends TreeNode
@override
// Coverage-ignore(suite): Not run.
void transformOrRemoveChildren(RemovingTransformer v) {
v.transformVariableDeclarationList(variables, this);
v.transformVariableInitializationList(variableInitializations, this);
if (condition != null) {
condition = v.transformOrRemoveExpression(condition!);
condition?.parent = this;
@@ -969,12 +998,12 @@ class ForMapEntry extends TreeNode
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < variableInitializations.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
variableInitializations[index],
includeModifiersAndType: index == 0,
);
}
@@ -996,7 +1025,11 @@ class PatternForMapEntry extends TreeNode
List<VariableDeclaration> intermediateVariables;
@override
final List<VariableDeclaration> variables;
final List<VariableInitialization> variableInitializations;
@override
// Coverage-ignore(suite): Not run.
List<VariableDeclaration> get variables => variableInitializations.cast();
@override
Expression? condition;
@@ -1010,23 +1043,23 @@ class PatternForMapEntry extends TreeNode
PatternForMapEntry({
required this.patternVariableDeclaration,
required this.intermediateVariables,
required this.variables,
required List<VariableInitialization> variables,
required this.condition,
required this.updates,
required this.body,
});
}) : variableInitializations = variables;
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
patternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < variableInitializations.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
variableInitializations[index],
includeModifiersAndType: index == 0,
);
}
@@ -1313,7 +1346,7 @@ MapLiteralEntry convertToMapEntry(
PatternForMapEntry result = new PatternForMapEntry(
patternVariableDeclaration: element.patternVariableDeclaration,
intermediateVariables: element.intermediateVariables,
variables: element.variables,
variables: element.variableInitializations,
condition: element.condition,
updates: element.updates,
body: convertToMapEntry(
@@ -1329,7 +1362,7 @@ MapLiteralEntry convertToMapEntry(
case ForElement():
ForMapEntry result = new ForMapEntry(
element.variables,
element.variableInitializations,
element.condition,
element.updates,
convertToMapEntry(
@@ -6052,7 +6052,7 @@ class StatementConstantEvaluator
@override
ExecutionStatus visitForStatement(ForStatement node) {
for (VariableDeclaration variable in node.variables) {
for (VariableInitialization variable in node.variableInitializations) {
final ExecutionStatus status = variable.accept(this);
if (status is! ProceedStatus) return status;
}
+7 -7
View File
@@ -282,7 +282,7 @@ class Forest {
ForElement createForElement(
int fileOffset,
List<VariableDeclaration> variables,
List<VariableInitialization> variables,
Expression? condition,
List<Expression> updates,
Expression body,
@@ -295,7 +295,7 @@ class Forest {
int fileOffset, {
required PatternVariableDeclaration patternVariableDeclaration,
required List<VariableDeclaration> intermediateVariables,
required List<VariableDeclaration> variables,
required List<VariableInitialization> variables,
required Expression? condition,
required List<Expression> updates,
required Expression body,
@@ -312,7 +312,7 @@ class Forest {
ForMapEntry createForMapEntry(
int fileOffset,
List<VariableDeclaration> variables,
List<VariableInitialization> variables,
Expression? condition,
List<Expression> updates,
MapLiteralEntry body,
@@ -325,7 +325,7 @@ class Forest {
int fileOffset, {
required PatternVariableDeclaration patternVariableDeclaration,
required List<VariableDeclaration> intermediateVariables,
required List<VariableDeclaration> variables,
required List<VariableInitialization> variableInitializations,
required Expression? condition,
required List<Expression> updates,
required MapLiteralEntry body,
@@ -333,7 +333,7 @@ class Forest {
return new PatternForMapEntry(
patternVariableDeclaration: patternVariableDeclaration,
intermediateVariables: intermediateVariables,
variables: variables,
variables: variableInitializations,
condition: condition,
updates: updates,
body: body,
@@ -505,7 +505,7 @@ class Forest {
/// Return a representation of a for statement.
Statement createForStatement(
int fileOffset,
List<VariableDeclaration>? variables,
List<VariableInitialization>? variables,
Expression? condition,
List<Expression> updaters,
Statement body,
@@ -1219,7 +1219,7 @@ class _VariablesDeclaration extends AuxiliaryStatement {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
printer.writeVariableInitialization(
declarations[index],
includeModifiersAndType: index == 0,
);
@@ -385,7 +385,7 @@ class Cascade extends InternalExpression {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableDeclaration(variable);
printer.writeVariableInitialization(variable);
printer.write(' in cascade {');
printer.incIndentation();
for (Expression expression in expressions) {
@@ -431,7 +431,7 @@ class DeferredCheck extends InternalExpression {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableDeclaration(variable);
printer.writeVariableInitialization(variable);
printer.write(' in ');
printer.writeExpression(expression);
}
@@ -888,7 +888,7 @@ class VariableDeclarationImpl extends VariableStatement
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.writeVariableDeclaration(
printer.writeVariableInitialization(
this,
isLate: isLate || lateGetter != null,
type: lateType ?? type,
@@ -1050,7 +1050,6 @@ mixin DelegatingVariableMixin on InternalExpressionVariableMixin
bool get isLate => astVariable.isLate;
@override
// Coverage-ignore(suite): Not run.
void set isLate(bool value) {
astVariable.isLate = value;
}
@@ -3477,9 +3477,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
@override
StatementInferenceResult visitForStatement(ForStatement node) {
_contextAllocationStrategy.enterScopeProvider(node);
List<VariableDeclaration>? variables;
for (int index = 0; index < node.variables.length; index++) {
VariableDeclaration variable = node.variables[index];
List<VariableInitialization>? variables;
for (int index = 0; index < node.variableInitializations.length; index++) {
VariableInitialization variable = node.variableInitializations[index];
if (variable.name == null) {
if (variable.initializer != null) {
ExpressionInferenceResult result = inferExpression(
@@ -3495,8 +3495,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
if (variableResult.hasChanged) {
// Coverage-ignore-block(suite): Not run.
if (variables == null) {
variables = <VariableDeclaration>[];
variables.addAll(node.variables.sublist(0, index));
variables = <VariableInitialization>[];
variables.addAll(node.variableInitializations.sublist(0, index));
}
if (variableResult.statementCount == 1) {
variables.add(variableResult.statement as VariableDeclaration);
@@ -3514,8 +3514,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
if (variables != null) {
// Coverage-ignore-block(suite): Not run.
node.variables.clear();
node.variables.addAll(variables);
node.variableInitializations.clear();
node.variableInitializations.addAll(variables);
setParents(variables, node);
}
flowAnalysis.for_conditionBegin(node);
@@ -4278,11 +4278,11 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<VariableDeclaration> declaredVariables =
patternVariableDeclaration.pattern.declaredVariables;
assert(declaredVariables.length == element.intermediateVariables.length);
assert(declaredVariables.length == element.variables.length);
assert(declaredVariables.length == element.variableInitializations.length);
for (int i = 0; i < declaredVariables.length; i++) {
DartType type = declaredVariables[i].type;
element.intermediateVariables[i].type = type;
element.variables[i].type = type;
element.variableInitializations[i].type = type;
}
return _inferForElementBase(
@@ -4314,9 +4314,13 @@ class InferenceVisitorImpl extends InferenceVisitorBase
Map<Expression, DartType> inferredConditionTypes,
) {
// TODO(johnniwinther): Use _visitStatements instead.
List<VariableDeclaration>? variables;
for (int index = 0; index < element.variables.length; index++) {
VariableDeclaration variable = element.variables[index];
List<VariableInitialization>? variables;
for (
int index = 0;
index < element.variableInitializations.length;
index++
) {
VariableInitialization variable = element.variableInitializations[index];
if (variable.name == null) {
if (variable.initializer != null) {
ExpressionInferenceResult initializerResult = inferExpression(
@@ -4334,7 +4338,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// Coverage-ignore-block(suite): Not run.
if (variables == null) {
variables = <VariableDeclaration>[];
variables.addAll(element.variables.sublist(0, index));
variables.addAll(element.variableInitializations.sublist(0, index));
}
if (variableResult.statementCount == 1) {
variables.add(variableResult.statement as VariableDeclaration);
@@ -4352,8 +4356,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
if (variables != null) {
// Coverage-ignore-block(suite): Not run.
element.variables.clear();
element.variables.addAll(variables);
element.variableInitializations.clear();
element.variableInitializations.addAll(variables);
setParents(variables, element);
}
@@ -5172,7 +5176,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: _createBlock(statements);
ForStatement loop = _createForStatement(
element.fileOffset,
element.variables,
element.variableInitializations,
element.condition,
element.updates,
loopBody,
@@ -5207,7 +5211,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
_createBlock(statements);
ForStatement loop = _createForStatement(
element.fileOffset,
element.variables,
element.variableInitializations,
element.condition,
element.updates,
loopBody,
@@ -5774,7 +5778,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: _createBlock(statements);
ForStatement loop = _createForStatement(
entry.fileOffset,
entry.variables,
entry.variableInitializations,
entry.condition,
entry.updates,
loopBody,
@@ -5807,7 +5811,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: _createBlock(statements);
ForStatement loop = _createForStatement(
entry.fileOffset,
entry.variables,
entry.variableInitializations,
entry.condition,
entry.updates,
loopBody,
@@ -6771,7 +6775,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
ForStatement _createForStatement(
int fileOffset,
List<VariableDeclaration> variables,
List<VariableInitialization> variables,
Expression? condition,
List<Expression> updates,
Statement body,
@@ -7367,11 +7371,11 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<VariableDeclaration> declaredVariables =
patternVariableDeclaration.pattern.declaredVariables;
assert(declaredVariables.length == entry.intermediateVariables.length);
assert(declaredVariables.length == entry.variables.length);
assert(declaredVariables.length == entry.variableInitializations.length);
for (int i = 0; i < declaredVariables.length; i++) {
DartType type = declaredVariables[i].type;
entry.intermediateVariables[i].type = type;
entry.variables[i].type = type;
entry.variableInitializations[i].type = type;
}
return _inferForMapEntryBase(
@@ -7427,9 +7431,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
_MapLiteralEntryOffsets offsets,
) {
// TODO(johnniwinther): Use _visitStatements instead.
List<VariableDeclaration>? variables;
for (int index = 0; index < entry.variables.length; index++) {
VariableDeclaration variable = entry.variables[index];
List<VariableInitialization>? variables;
for (int index = 0; index < entry.variableInitializations.length; index++) {
VariableInitialization variable = entry.variableInitializations[index];
if (variable.name == null) {
if (variable.initializer != null) {
ExpressionInferenceResult result = inferExpression(
@@ -7446,7 +7450,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// Coverage-ignore-block(suite): Not run.
if (variables == null) {
variables = <VariableDeclaration>[];
variables.addAll(entry.variables.sublist(0, index));
variables.addAll(entry.variableInitializations.sublist(0, index));
}
if (variableResult.statementCount == 1) {
variables.add(variableResult.statement as VariableDeclaration);
@@ -7464,8 +7468,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
if (variables != null) {
// Coverage-ignore-block(suite): Not run.
entry.variables.clear();
entry.variables.addAll(variables);
entry.variableInitializations.clear();
entry.variableInitializations.addAll(variables);
setParents(variables, entry);
}
@@ -8211,7 +8215,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
PatternForElement result = new PatternForElement(
patternVariableDeclaration: entry.patternVariableDeclaration,
intermediateVariables: entry.intermediateVariables,
variables: entry.variables,
variables: entry.variableInitializations,
condition: entry.condition,
updates: entry.updates,
body: convertToElement(entry.body, onConvertMapEntry),
@@ -8220,7 +8224,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
return result;
case ForMapEntry():
ForElement result = new ForElement(
entry.variables,
entry.variableInitializations,
entry.condition,
entry.updates,
convertToElement(entry.body, onConvertMapEntry),
@@ -69,6 +69,8 @@ class TypeArgumentsVisitor extends VerifyingAnalysis {
'VariableDeclaration',
uri: astUri,
);
InterfaceType variableInitializationType = interface
.createInterfaceType('VariableInitialization', uri: astUri);
DartType typeArgument = receiver.arguments.types.single;
if (interface.isSubtypeOf(typeArgument, expressionType) &&
typeArgument != expressionType) {
@@ -102,6 +104,19 @@ class TypeArgumentsVisitor extends VerifyingAnalysis {
"${typeArgument} instead of ${variableDeclarationType}",
);
}
} else if (interface.isSubtypeOf(
typeArgument,
variableInitializationType,
)) {
// [VariableInitialization] is used as an exclusive member of, for
// instance, `ForStatement.variableInitializations`.
if (typeArgument != variableInitializationType) {
registerError(
node,
"map().toList() with type argument "
"${typeArgument} instead of ${variableInitializationType}",
);
}
} else if (typeArgument != statementType) {
registerError(
node,
@@ -11,3 +11,19 @@ testCaptured() {
int a = 0;
return () => a;
}
testForCounterNotCaptured() {
int a = 0;
for (int i = 0; i < 10; i++) {
a += i;
}
return a;
}
testForCounterCaptured() {
List<Function> closures = [];
for (int i = 0; i < 10; i++) {
closures.add(() => i);
}
return closures;
}
@@ -18,3 +18,33 @@ static method testCaptured() → dynamic /* scope=[
a := 0;
return () → core::int => a;
}
static method testForCounterNotCaptured() → dynamic /* scope=[
not-captured VariableContext([
local-variable a;
]),
] */ {
a := 0;
for /* scope=[
not-captured VariableContext([
local-variable i;
]),
] */ (i := 0; i.{core::num::<}(10){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
a = a.{core::num::+}(i){(core::num) → core::int};
}
return a;
}
static method testForCounterCaptured() → dynamic /* scope=[
not-captured VariableContext([
local-variable closures;
]),
] */ {
closures := <core::Function>[];
for /* scope=[
captured VariableContext([
local-variable i;
]),
] */ (i := 0; i.{core::num::<}(10){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
closures.{core::List::add}(() → core::int => i){(core::Function) → void};
}
return closures;
}
@@ -18,3 +18,33 @@ static method testCaptured() → dynamic /* scope=[
a := 0;
return () → core::int => a;
}
static method testForCounterNotCaptured() → dynamic /* scope=[
not-captured VariableContext([
local-variable a;
]),
] */ {
a := 0;
for /* scope=[
not-captured VariableContext([
local-variable i;
]),
] */ (i := 0; i.{core::num::<}(10){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
a = a.{core::num::+}(i){(core::num) → core::int};
}
return a;
}
static method testForCounterCaptured() → dynamic /* scope=[
not-captured VariableContext([
local-variable closures;
]),
] */ {
closures := <core::Function>[];
for /* scope=[
captured VariableContext([
local-variable i;
]),
] */ (i := 0; i.{core::num::<}(10){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
closures.{core::List::add}(() → core::int => i){(core::Function) → void};
}
return closures;
}
@@ -5,3 +5,7 @@ static method testNotCaptured() → dynamic
;
static method testCaptured() → dynamic
;
static method testForCounterNotCaptured() → dynamic
;
static method testForCounterCaptured() → dynamic
;
@@ -1,3 +1,7 @@
testNotCaptured() {}
testCaptured() {}
testForCounterNotCaptured() {}
testForCounterCaptured() {}
@@ -1,3 +1,7 @@
testCaptured() {}
testForCounterCaptured() {}
testForCounterNotCaptured() {}
testNotCaptured() {}
+1 -1
View File
@@ -129,7 +129,7 @@ const Map<String?, Map<String, FieldRule?>> _fieldRuleMap = {
'LocalFunctionInvocation': {'variable': FieldRule(isDeclaration: false)},
'LocalVariable': {'variableInitialization': FieldRule(isDeclaration: false)},
'BreakStatement': {'target': FieldRule(isDeclaration: false)},
'ForStatement': {'variables': FieldRule(isDeclaration: true)},
'ForStatement': {'variableInitializations': FieldRule(isDeclaration: true)},
'ForInStatement': {'variable': FieldRule(isDeclaration: true)},
'SwitchStatement': {'cases': FieldRule(isDeclaration: true)},
'ContinueSwitchStatement': {'target': FieldRule(isDeclaration: false)},
+2 -1
View File
@@ -534,7 +534,8 @@ class CloneVisitorNotMembers
@override
TreeNode visitForStatement(ForStatement node) {
List<VariableDeclaration> variables = node.variables.map(clone).toList();
List<VariableInitialization> variables =
node.variableInitializations.map(clone).toList();
return new ForStatement(variables, cloneOptional(node.condition),
node.updates.map(clone).toList(), clone(node.body));
}
+1 -1
View File
@@ -4845,7 +4845,7 @@ class Let extends Expression {
@override
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableDeclaration(variable);
printer.writeVariableInitialization(variable);
printer.write(' in ');
printer.writeExpression(body);
}
+17 -13
View File
@@ -530,7 +530,10 @@ class DoStatement extends Statement implements LoopStatement {
}
class ForStatement extends Statement implements LoopStatement, ScopeProvider {
final List<VariableDeclaration> variables; // May be empty, but not null.
// May be empty, but not null.
final List<VariableInitialization> variableInitializations;
List<VariableDeclaration> get variables => variableInitializations.cast();
Expression? condition; // May be null.
final List<Expression> updates; // May be empty, but not null.
@@ -540,8 +543,9 @@ class ForStatement extends Statement implements LoopStatement, ScopeProvider {
@override
Scope? scope;
ForStatement(this.variables, this.condition, this.updates, this.body) {
setParents(variables, this);
ForStatement(
this.variableInitializations, this.condition, this.updates, this.body) {
setParents(variableInitializations, this);
condition?.parent = this;
setParents(updates, this);
body.parent = this;
@@ -556,7 +560,7 @@ class ForStatement extends Statement implements LoopStatement, ScopeProvider {
@override
void visitChildren(Visitor v) {
visitList(variables, v);
visitList(variableInitializations, v);
condition?.accept(v);
visitList(updates, v);
body.accept(v);
@@ -564,7 +568,7 @@ class ForStatement extends Statement implements LoopStatement, ScopeProvider {
@override
void transformChildren(Transformer v) {
v.transformList(variables, this);
v.transformList(variableInitializations, this);
if (condition != null) {
condition = v.transform(condition!);
condition?.parent = this;
@@ -576,7 +580,7 @@ class ForStatement extends Statement implements LoopStatement, ScopeProvider {
@override
void transformOrRemoveChildren(RemovingTransformer v) {
v.transformVariableDeclarationList(variables, this);
v.transformVariableInitializationList(variableInitializations, this);
if (condition != null) {
condition = v.transformOrRemoveExpression(condition!);
condition?.parent = this;
@@ -594,11 +598,11 @@ class ForStatement extends Statement implements LoopStatement, ScopeProvider {
@override
void toTextInternal(AstPrinter printer) {
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < variableInitializations.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(variables[index],
printer.writeVariableInitialization(variableInitializations[index],
includeModifiersAndType: index == 0);
}
printer.write('; ');
@@ -761,7 +765,7 @@ class ForInStatement extends Statement implements LoopStatement, ScopeProvider {
@override
void toTextInternal(AstPrinter printer) {
printer.write('for (');
printer.writeVariableDeclaration(variable);
printer.writeVariableInitialization(variable);
printer.write(' in ');
printer.writeExpression(iterable);
@@ -1274,11 +1278,11 @@ class Catch extends TreeNode implements ScopeProvider {
printer.write(' ');
}
printer.write('catch (');
printer.writeVariableDeclaration(exception!,
printer.writeVariableInitialization(exception!,
includeModifiersAndType: false);
if (stackTrace != null) {
printer.write(', ');
printer.writeVariableDeclaration(stackTrace!,
printer.writeVariableInitialization(stackTrace!,
includeModifiersAndType: false);
}
printer.write(') ');
@@ -1898,13 +1902,13 @@ class VariableStatement extends Statement implements VariableDeclaration {
@override
String toStringInternal() {
AstPrinter printer = new AstPrinter(defaultAstTextStrategy);
printer.writeVariableDeclaration(this, includeInitializer: false);
printer.writeVariableInitialization(this, includeInitializer: false);
return printer.getText();
}
@override
void toTextInternal(AstPrinter printer) {
printer.writeVariableDeclaration(this);
printer.writeVariableInitialization(this);
printer.write(';');
}
+6 -3
View File
@@ -5131,7 +5131,7 @@ class EquivalenceStrategy {
if (other is! ForStatement) return false;
visitor.pushNodeState(node, other);
bool result = true;
if (!checkForStatement_variables(visitor, node, other)) {
if (!checkForStatement_variableInitializations(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
if (!checkForStatement_condition(visitor, node, other)) {
@@ -9542,10 +9542,13 @@ class EquivalenceStrategy {
return checkStatement_fileOffset(visitor, node, other);
}
bool checkForStatement_variables(
bool checkForStatement_variableInitializations(
EquivalenceVisitor visitor, ForStatement node, ForStatement other) {
return visitor.checkLists(
node.variables, other.variables, visitor.checkNodes, 'variables');
node.variableInitializations,
other.variableInitializations,
visitor.checkNodes,
'variableInitializations');
}
bool checkForStatement_condition(
+5 -5
View File
@@ -467,7 +467,7 @@ class AstPrinter {
node.toTextInternal(this, includeTypeArguments: includeTypeArguments);
}
/// Writes the variable declaration [node] to the printer buffer.
/// Writes the [VariableInitialization] [node] to the printer buffer.
///
/// If [includeModifiersAndType] is `true`, the declaration is prefixed by
/// the modifiers and declared type of the variable. Otherwise only the
@@ -475,7 +475,7 @@ class AstPrinter {
///
/// If [isLate] and [type] are provided, these values are used instead of
/// the corresponding properties on [node].
void writeVariableDeclaration(VariableDeclaration node,
void writeVariableInitialization(VariableInitialization node,
{bool includeModifiersAndType = true,
bool? isLate,
DartType? type,
@@ -496,7 +496,7 @@ class AstPrinter {
writeType(type ?? node.type);
_sb.write(' ');
}
_sb.write(getVariableName(node));
_sb.write(getVariableName(node.variable));
if (includeInitializer && node.initializer != null && !node.isRequired) {
_sb.write(' = ');
writeExpression(node.initializer!);
@@ -556,7 +556,7 @@ class AstPrinter {
if (index == node.requiredParameterCount) {
_sb.write('[');
}
writeVariableDeclaration(node.positionalParameters[index]);
writeVariableInitialization(node.positionalParameters[index]);
}
if (node.requiredParameterCount < node.positionalParameters.length) {
_sb.write(']');
@@ -570,7 +570,7 @@ class AstPrinter {
if (index > 0) {
_sb.write(', ');
}
writeVariableDeclaration(node.namedParameters[index]);
writeVariableInitialization(node.namedParameters[index]);
}
_sb.write('}');
}
+33 -22
View File
@@ -224,7 +224,7 @@ class NameSystem {
}
abstract class Annotator {
String annotateVariable(Printer printer, VariableDeclaration node);
String annotateVariable(Printer printer, VariableInitialization node);
String annotateReturn(Printer printer, FunctionNode node);
String annotateField(Printer printer, Field node);
}
@@ -1103,6 +1103,7 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
writeVariableContext(context, separator: separator);
}
--indentation;
writeIndentation();
writeWord('] */');
}
@@ -2422,8 +2423,12 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
void visitForStatement(ForStatement node) {
writeIndentation();
writeSpaced('for');
if (node.scope case Scope scope?) {
writeScope(scope);
ensureSpace();
}
writeSymbol('(');
writeList(node.variables, writeVariableDeclaration);
writeList(node.variableInitializations, writeVariableInitialization);
writeComma(';');
Expression? condition = node.condition;
if (condition != null) {
@@ -2647,26 +2652,32 @@ class Printer extends VisitorDefault<void> with VisitorVoidMixin {
void writeVariableInitialization(
VariableInitialization node,
) {
if (showOffsets) writeWord("[${node.fileOffset}]");
if (showMetadata) writeMetadata(node);
writeAnnotationList(node.annotations, separateLines: false);
writeModifier(node.isErroneouslyInitialized, 'erroneously-initialized');
bool hasImplicitInitializer = node.initializer is NullLiteral ||
(node.initializer is ConstantExpression &&
(node.initializer as ConstantExpression).constant is NullConstant);
if ((node.initializer == null || hasImplicitInitializer) &&
node.hasDeclaredInitializer) {
writeModifier(node.hasDeclaredInitializer, 'has-declared-initializer');
} else if (node.initializer != null &&
!hasImplicitInitializer &&
!node.hasDeclaredInitializer) {
writeModifier(node.hasDeclaredInitializer, 'has-no-declared-initializer');
}
writeWord(getVariableName(node.variable));
Expression? initializer = node.initializer;
if (initializer != null) {
writeSpaced(':=');
writeExpression(initializer);
if (node is VariableDeclaration) {
writeVariableDeclaration(node);
} else {
if (showOffsets) writeWord("[${node.fileOffset}]");
if (showMetadata) writeMetadata(node);
writeAnnotationList(node.annotations, separateLines: false);
writeModifier(node.isErroneouslyInitialized, 'erroneously-initialized');
bool hasImplicitInitializer = node.initializer is NullLiteral ||
(node.initializer is ConstantExpression &&
(node.initializer as ConstantExpression).constant
is NullConstant);
if ((node.initializer == null || hasImplicitInitializer) &&
node.hasDeclaredInitializer) {
writeModifier(node.hasDeclaredInitializer, 'has-declared-initializer');
} else if (node.initializer != null &&
!hasImplicitInitializer &&
!node.hasDeclaredInitializer) {
writeModifier(
node.hasDeclaredInitializer, 'has-no-declared-initializer');
}
writeWord(getVariableName(node.variable));
Expression? initializer = node.initializer;
if (initializer != null) {
writeSpaced(':=');
writeExpression(initializer);
}
}
}
+6 -8
View File
@@ -1023,7 +1023,7 @@ class TypeCheckingVisitor
@override
void visitForStatement(ForStatement node) {
node.variables.forEach(visitVariableDeclaration);
node.variableInitializations.forEach(visitVariableInitialization);
if (node.condition != null) {
node.condition = checkExpressionAndAssignability(
node.condition!, environment.coreTypes.boolNonNullableRawType);
@@ -1093,6 +1093,11 @@ class TypeCheckingVisitor
@override
void visitVariableDeclaration(VariableDeclaration node) {
visitVariableInitialization(node);
}
@override
void visitVariableInitialization(VariableInitialization node) {
if (node.initializer != null) {
node.initializer =
checkExpressionAndAssignability(node.initializer!, node.type);
@@ -1347,13 +1352,6 @@ class TypeCheckingVisitor
// TODO(johnniwinther): Implement this.
}
@override
void visitVariableInitialization(VariableInitialization node) {
// TODO(cstefantsova): Implement visitVariableInitialization.
throw new UnimplementedError(
"Unimplemented support for $node (${node.runtimeType}).");
}
@override
DartType visitVariableRead(VariableRead node) {
// TODO(cstefantsova): Implement visitVariableRead.
+10
View File
@@ -2474,6 +2474,16 @@ class RemovingTransformer extends TreeVisitor1Default<TreeNode, TreeNode?> {
transformList(nodes, parent, dummyVariableDeclaration);
}
/// Transforms or removes [VariableInitialization] nodes in [nodes] as
/// children of [parent].
///
/// This is convenience method for calling [transformList] with removal
/// sentinel for [VariableInitialization] nodes.
void transformVariableInitializationList(
List<VariableInitialization> nodes, TreeNode parent) {
transformList(nodes, parent, dummyVariableDeclaration);
}
/// Transforms or removes [T] nodes in [nodes] as children of [parent] by
/// calling [transformOrRemove] using [removalSentinel] as the removal
/// sentinel.