[cfe][InternalNodes] Add more internal nodes

This adds internal nodes for VariableStatement, VariableDeclaration, Let, and ForStatement. The prepares for separating Variable from InternalVariable and allows for the removal of Variable.asVariableDeclaration.

Change-Id: Ib0593f64b3d22ce99c187ab4af32c8dc8cbea6e9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/509980
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
This commit is contained in:
Johnni Winther
2026-06-09 05:27:48 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 90d89a0ca1
commit ac477b9233
10 changed files with 655 additions and 332 deletions
+27 -25
View File
@@ -3326,14 +3326,14 @@ class BodyBuilderImpl extends StackListenerImpl
}
pushNewLocalVariable(initializer, equalsToken: assignmentOperator);
if (isLate) {
VariableDeclaration node = peek() as VariableDeclaration;
InternalVariableDeclaration node = peek() as InternalVariableDeclaration;
// This is matched by the call to [beginNode] in
// [beginVariableInitializer].
// TODO(62401): Remove the cast when the flow analysis uses
// [InternalExpressionVariable]s.
assignedVariables.storeInfo(
(node.variable as InternalVariable).astVariable,
node.variable.astVariable,
assignedVariablesInfo!,
);
}
@@ -3384,7 +3384,7 @@ class BodyBuilderImpl extends StackListenerImpl
name = createWildcardVariableName(wildcardVariableIndex);
wildcardVariableIndex++;
}
VariableDeclaration variableDeclaration;
InternalVariableDeclaration variableDeclaration;
InternalVariable internalVariable;
if (isLate) {
internalVariable = intern.createLateVariable(
@@ -3510,7 +3510,8 @@ class BodyBuilderImpl extends StackListenerImpl
push(node);
return;
}
VariableDeclaration declaration = node as VariableDeclaration;
InternalVariableDeclaration declaration =
node as InternalVariableDeclaration;
declaration.variable.fileOffset = declaration.fileOffset =
nameToken.charOffset;
push(declaration);
@@ -3520,7 +3521,7 @@ class BodyBuilderImpl extends StackListenerImpl
// the scope.
if (!(libraryFeatures.wildcardVariables.isEnabled &&
declaration.variable.isWildcard)) {
declareVariable(declaration.variable as InternalVariable, _localScope);
declareVariable(declaration.variable, _localScope);
}
}
@@ -3567,7 +3568,8 @@ class BodyBuilderImpl extends StackListenerImpl
push(node);
return;
}
VariableDeclaration declaration = node as VariableDeclaration;
InternalVariableDeclaration declaration =
node as InternalVariableDeclaration;
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
declaration.variable.addAnnotation(annotations[i]);
@@ -3578,11 +3580,11 @@ class BodyBuilderImpl extends StackListenerImpl
// [endToken]?
push(intern.createVariableStatement(declaration));
} else {
List<VariableDeclaration>? variables =
const FixedNullableList<VariableDeclaration>().popNonNullable(
List<InternalVariableDeclaration>? variables =
const FixedNullableList<InternalVariableDeclaration>().popNonNullable(
stack,
count,
dummyVariableDeclaration,
dummyInternalVariableDeclaration,
);
constantContext = pop() as ConstantContext;
currentLocalVariableType = pop(NullValues.Type) as DartType?;
@@ -3593,7 +3595,7 @@ class BodyBuilderImpl extends StackListenerImpl
return;
}
if (annotations != null) {
VariableDeclaration first = variables.first;
InternalVariableDeclaration first = variables.first;
for (int i = 0; i < annotations.length; i++) {
first.variable.addAnnotation(annotations[i]);
}
@@ -3704,7 +3706,7 @@ class BodyBuilderImpl extends StackListenerImpl
}
}
List<VariableDeclaration>? _buildForLoopVariableDeclarations(
List<InternalVariableDeclaration>? _buildForLoopVariableDeclarations(
variableOrExpression,
) {
// TODO(ahe): This can be simplified now that we have the events
@@ -3712,16 +3714,16 @@ class BodyBuilderImpl extends StackListenerImpl
if (variableOrExpression is Generator) {
variableOrExpression = variableOrExpression.buildForEffect();
}
if (variableOrExpression is VariableStatement) {
if (variableOrExpression is InternalVariableStatement) {
// TODO(johnniwinther): Avoid parsing variable declarations initializers
// in for statements as statements.
VariableDeclaration variableDeclaration =
InternalVariableDeclaration variableDeclaration =
variableOrExpression.declaration;
// Late for loop variables are not supported. An error has already been
// reported by the parser.
variableDeclaration.variable.isLate = false;
return [variableDeclaration];
} else if (variableOrExpression is VariableDeclaration) {
} else if (variableOrExpression is InternalVariableDeclaration) {
// Coverage-ignore-block(suite): Not run.
// Late for loop variables are not supported. An error has already been
// reported by the parser.
@@ -3746,7 +3748,7 @@ class BodyBuilderImpl extends StackListenerImpl
);
} else if (variableOrExpression is List<Object>) {
// Coverage-ignore-block(suite): Not run.
List<VariableDeclaration> variables = [];
List<InternalVariableDeclaration> variables = [];
for (Object v in variableOrExpression) {
variables.addAll(_buildForLoopVariableDeclarations(v)!);
}
@@ -3790,8 +3792,8 @@ class BodyBuilderImpl extends StackListenerImpl
// If the declaration is of the form `for (final x in ...)`, then we may
// have erroneously set the `isStaticLate` flag, so un-set it.
Object? declaration = peek();
if (declaration case VariableStatement(
declaration: VariableDeclaration(:VariableDeclarationImpl variable),
if (declaration case InternalVariableStatement(
declaration: InternalVariableDeclaration(:InternalVariable variable),
)) {
variable.isStaticLate = false;
}
@@ -3967,8 +3969,8 @@ class BodyBuilderImpl extends StackListenerImpl
.popNode();
Object? variableOrExpression = pop();
List<VariableDeclaration>? variables;
List<VariableDeclaration>? intermediateVariables;
List<InternalVariableDeclaration>? variables;
List<InternalVariableDeclaration>? intermediateVariables;
if (variableOrExpression is InternalPatternVariableDeclaration) {
variables = (pop() as List<InternalVariable>)
.map(intern.createVariableDeclaration)
@@ -4090,8 +4092,8 @@ class BodyBuilderImpl extends StackListenerImpl
.deferNode();
Object? variableOrExpression = pop();
List<VariableDeclaration>? variables;
List<VariableDeclaration>? intermediateVariables;
List<InternalVariableDeclaration>? variables;
List<InternalVariableDeclaration>? intermediateVariables;
if (variableOrExpression is InternalPatternVariableDeclaration) {
variables = (pop() as List<InternalVariable>)
.map(intern.createVariableDeclaration)
@@ -4142,7 +4144,7 @@ class BodyBuilderImpl extends StackListenerImpl
fileEndOffset: result.fileOffset,
[
variableOrExpression,
for (VariableDeclaration intermediateVariable
for (InternalVariableDeclaration intermediateVariable
in intermediateVariables!)
intern.createVariableStatement(intermediateVariable),
result,
@@ -8380,10 +8382,10 @@ class BodyBuilderImpl extends StackListenerImpl
required Token inToken,
required Object? lvalue,
}) {
if (lvalue is VariableStatement) {
if (lvalue is InternalVariableStatement) {
// TODO(johnniwinther): Avoid parsing variable declarations in
// for-in statements as statements.
VariableDeclaration declaration = lvalue.declaration;
InternalVariableDeclaration declaration = lvalue.declaration;
// Variable initializers are not supported. An error has already been
// reported by the parser.
declaration.variable.initializer = null;
@@ -8407,7 +8409,7 @@ class BodyBuilderImpl extends StackListenerImpl
variableDeclaration: declaration,
error: error,
);
} else if (lvalue is VariableDeclaration) {
} else if (lvalue is InternalVariableDeclaration) {
// Coverage-ignore-block(suite): Not run.
// Variable initializers are not supported. An error has already been
// reported by the parser.
+49 -35
View File
@@ -222,7 +222,7 @@ class ForElement extends ControlFlowElement
implements ForElementBase {
// May be empty, but not null.
@override
final List<VariableDeclaration> variables;
final List<InternalVariableDeclaration> internalVariables;
@override
Expression? condition; // May be null.
@@ -233,8 +233,11 @@ class ForElement extends ControlFlowElement
@override
Expression body;
new(this.variables, this.condition, this.updates, this.body) {
setParents(variables, this);
@override
late List<VariableDeclaration> variables;
new(this.internalVariables, this.condition, this.updates, this.body) {
setParents(internalVariables, this);
condition?.parent = this;
setParents(updates, this);
body.parent = this;
@@ -252,7 +255,7 @@ class ForElement extends ControlFlowElement
}
if (bodyEntry == null) return null;
ForMapEntry result = new ForMapEntry(
variables,
internalVariables,
condition,
updates,
bodyEntry,
@@ -270,12 +273,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 < internalVariables.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
internalVariables[index].variable.astVariable,
includeModifiersAndType: index == 0,
);
}
@@ -307,7 +310,7 @@ class ForInElement extends ControlFlowElement
/// [ScopeProvider] nodes in the output.
Scope? scope;
Variable? variable;
late Variable variable;
ForInEncoding? encoding;
@@ -318,7 +321,6 @@ class ForInElement extends ControlFlowElement
required this.isAsync,
required int fileOffset,
required this.forOffset,
this.variable,
this.encoding,
}) {
this.fileOffset = fileOffset;
@@ -354,7 +356,6 @@ class ForInElement extends ControlFlowElement
isAsync: isAsync,
fileOffset: fileOffset,
forOffset: forOffset,
variable: variable,
encoding: encoding,
);
onConvertElement(this, result);
@@ -457,24 +458,27 @@ class IfCaseElement extends ControlFlowElementImpl
}
abstract interface class ForElementBase implements AuxiliaryExpression {
List<VariableDeclaration> get variables;
List<InternalVariableDeclaration> get internalVariables;
abstract Expression? condition;
List<Expression> get updates;
abstract Expression body;
/// [VariableDeclaration]s computed after inference of [internalVariables].
abstract List<VariableDeclaration> variables;
}
class PatternForElement extends ControlFlowElementImpl
with ControlFlowElementMixin
implements ForElementBase {
InternalPatternVariableDeclaration internalPatternVariableDeclaration;
List<VariableDeclaration> intermediateVariables;
List<InternalVariableDeclaration> intermediateVariables;
// May be empty, but not null.
@override
final List<VariableDeclaration> variables;
final List<InternalVariableDeclaration> internalVariables;
@override
Expression? condition; // May be null.
@@ -489,10 +493,13 @@ class PatternForElement extends ControlFlowElementImpl
/// [internalPatternVariableDeclaration].
late PatternVariableDeclaration patternVariableDeclaration;
@override
late List<VariableDeclaration> variables;
new({
required this.internalPatternVariableDeclaration,
required this.intermediateVariables,
required this.variables,
required this.internalVariables,
required this.condition,
required this.updates,
required this.body,
@@ -511,12 +518,12 @@ class PatternForElement extends ControlFlowElementImpl
void toTextInternal(AstPrinter printer) {
internalPatternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < internalVariables.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
internalVariables[index].variable.astVariable,
includeModifiersAndType: index == 0,
);
}
@@ -683,13 +690,16 @@ class IfMapEntry extends TreeNode
}
abstract interface class ForMapEntryBase implements TreeNode, MapLiteralEntry {
List<VariableDeclaration> get variables;
List<InternalVariableDeclaration> get internalVariables;
abstract Expression? condition;
List<Expression> get updates;
abstract MapLiteralEntry body;
/// [VariableDeclaration]s computed after inference of [internalVariables].
abstract List<VariableDeclaration> variables;
}
/// A 'for' element in a map literal.
@@ -698,7 +708,7 @@ class ForMapEntry extends TreeNode
implements ForMapEntryBase, ControlFlowMapEntry {
// May be empty, but not null.
@override
final List<VariableDeclaration> variables;
final List<InternalVariableDeclaration> internalVariables;
@override
Expression? condition; // May be null.
@@ -709,8 +719,11 @@ class ForMapEntry extends TreeNode
@override
MapLiteralEntry body;
new(this.variables, this.condition, this.updates, this.body) {
setParents(variables, this);
@override
late List<VariableDeclaration> variables;
new(this.internalVariables, this.condition, this.updates, this.body) {
setParents(internalVariables, this);
condition?.parent = this;
setParents(updates, this);
body.parent = this;
@@ -725,12 +738,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 < internalVariables.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
internalVariables[index].variable.astVariable,
includeModifiersAndType: index == 0,
);
}
@@ -749,10 +762,10 @@ class PatternForMapEntry extends TreeNode
with InternalTreeNode, ControlFlowMapEntryMixin
implements ForMapEntryBase, ControlFlowMapEntry {
InternalPatternVariableDeclaration internalPatternVariableDeclaration;
List<VariableDeclaration> intermediateVariables;
List<InternalVariableDeclaration> intermediateVariables;
@override
final List<VariableDeclaration> variables;
final List<InternalVariableDeclaration> internalVariables;
@override
Expression? condition;
@@ -767,10 +780,13 @@ class PatternForMapEntry extends TreeNode
/// [internalPatternVariableDeclaration].
late PatternVariableDeclaration patternVariableDeclaration;
@override
late List<VariableDeclaration> variables;
new({
required this.internalPatternVariableDeclaration,
required this.intermediateVariables,
required this.variables,
required this.internalVariables,
required this.condition,
required this.updates,
required this.body,
@@ -781,12 +797,12 @@ class PatternForMapEntry extends TreeNode
void toTextInternal(AstPrinter printer) {
internalPatternVariableDeclaration.toTextInternal(printer);
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
for (int index = 0; index < internalVariables.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
variables[index],
printer.writeVariableInitialization(
internalVariables[index].variable.astVariable,
includeModifiersAndType: index == 0,
);
}
@@ -824,7 +840,7 @@ class ForInMapEntry extends TreeNode
/// [ScopeProvider] nodes in the output.
Scope? scope;
Variable? variable;
late Variable variable;
ForInEncoding? encoding;
@@ -835,7 +851,6 @@ class ForInMapEntry extends TreeNode
required this.isAsync,
required int fileOffset,
required this.forOffset,
this.variable,
this.encoding,
}) {
this.fileOffset = fileOffset;
@@ -1020,7 +1035,7 @@ MapLiteralEntry convertToMapEntry(
internalPatternVariableDeclaration:
element.internalPatternVariableDeclaration,
intermediateVariables: element.intermediateVariables,
variables: element.variables,
internalVariables: element.internalVariables,
condition: element.condition,
updates: element.updates,
body: convertToMapEntry(
@@ -1036,7 +1051,7 @@ MapLiteralEntry convertToMapEntry(
case ForElement():
ForMapEntry result = new ForMapEntry(
element.variables,
element.internalVariables,
element.condition,
element.updates,
convertToMapEntry(
@@ -1064,7 +1079,6 @@ MapLiteralEntry convertToMapEntry(
fileOffset: element.fileOffset,
forOffset: element.forOffset,
isAsync: element.isAsync,
variable: element.variable,
encoding: element.encoding,
);
onConvertElement(element, result);
@@ -297,10 +297,14 @@ EqualsNull createEqualsNull(Expression expression, {required int fileOffset}) {
}
/// Creates an [ExpressionStatement] of [expression] using the file offset of
/// [expression] for the file offset of the statement.
ExpressionStatement createExpressionStatement(Expression expression) {
/// [expression] for the file offset of the statement, unless provided directly
/// through [fileOffset].
ExpressionStatement createExpressionStatement(
Expression expression, {
int? fileOffset,
}) {
return new ExpressionStatement(expression)
..fileOffset = expression.fileOffset;
..fileOffset = fileOffset ?? expression.fileOffset;
}
FieldInitializer createFieldInitializer(
@@ -599,8 +603,9 @@ LateVariable createLateVariable({
/// Creates a [Let] of [variable] with the given [body] using
/// `variable.fileOffset` as the file offset for the let.
Let createLet(Variable variable, Expression body) {
return new Let(variable, body)..fileOffset = variable.fileOffset;
Let createLet(Variable variable, Expression body, {int? fileOffset}) {
return new Let(variable, body)
..fileOffset = fileOffset ?? variable.fileOffset;
}
/// Creates a [Let] with the [effect] as the variable initializer and the
@@ -1281,8 +1286,14 @@ Variable createVariableCache(Expression expression, DartType type) {
..fileOffset = expression.fileOffset;
}
VariableDeclaration createVariableDeclaration(Variable variable) {
return new VariableDeclaration(variable)..fileOffset = variable.fileOffset;
VariableDeclaration createVariableDeclaration(
Variable variable, {
List<VariableContext>? capturedContexts,
int? fileOffset,
}) {
return new VariableDeclaration(variable)
..capturedContexts = capturedContexts
..fileOffset = fileOffset ?? variable.fileOffset;
}
/// Creates a [VariableGet] of [variable] using `variable.fileOffset` as the
@@ -1330,9 +1341,12 @@ Expression createVariableSet(
}
}
VariableStatement createVariableStatement(VariableDeclaration declaration) {
VariableStatement createVariableStatement(
VariableDeclaration declaration, {
int? fileOffset,
}) {
return new VariableStatement(declaration)
..fileOffset = declaration.fileOffset;
..fileOffset = fileOffset ?? declaration.fileOffset;
}
WildcardPattern createWildcardPattern({
@@ -1354,3 +1368,16 @@ Catch createCatch({
..scope = scope
..fileOffset = fileOffset;
}
ForStatement createForStatement({
required List<VariableDeclaration> variables,
required Expression? condition,
required List<Expression> updates,
required Statement body,
required Scope? scope,
required int fileOffset,
}) {
return new ForStatement(variables, condition, updates, body)
..scope = scope
..fileOffset = fileOffset;
}
+175 -34
View File
@@ -657,7 +657,7 @@ class Cascade extends InternalExpression {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableInitialization(variable.asVariableDeclaration);
printer.writeVariableInitialization(variable.astVariable);
printer.write(' in cascade {');
printer.incIndentation();
for (Expression expression in expressions) {
@@ -670,7 +670,7 @@ class Cascade extends InternalExpression {
printer.newLine();
}
printer.write('} => ');
printer.write(printer.getVariableName(variable.asVariableDeclaration));
printer.write(printer.getVariableName(variable.astVariable));
}
}
@@ -713,7 +713,7 @@ class AnonymousMethodExpression extends InternalExpression {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableInitialization(variable.asVariableDeclaration);
printer.writeVariableInitialization(variable.astVariable);
printer.write(' in ');
printer.writeExpression(body);
}
@@ -758,7 +758,7 @@ class AnonymousMethodBlock extends InternalExpression {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableInitialization(variable.asVariableDeclaration);
printer.writeVariableInitialization(variable.astVariable);
printer.write(' in ');
printer.writeStatement(body);
}
@@ -794,7 +794,7 @@ class DeferredCheck extends InternalExpression {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableInitialization(variable.asVariableDeclaration);
printer.writeVariableInitialization(variable.astVariable);
printer.write(' in ');
printer.writeExpression(expression);
}
@@ -1418,6 +1418,7 @@ class InternalLateVariable extends TreeNode
variableDeclaration?.capturedContexts;
@override
// Coverage-ignore(suite): Not run.
void set capturedContexts(List<VariableContext>? value) {
variableDeclaration!.capturedContexts = value;
}
@@ -1426,6 +1427,7 @@ class InternalLateVariable extends TreeNode
int fileEqualsOffset = TreeNode.noOffset;
@override
// Coverage-ignore(suite): Not run.
Variable get variable => this;
@override
@@ -1951,10 +1953,12 @@ mixin DelegatingVariableMixin on InternalVariableMixin
}
@override
// Coverage-ignore(suite): Not run.
VariableDeclaration? get variableDeclaration =>
astVariable.variableDeclaration;
@override
// Coverage-ignore(suite): Not run.
void set variableDeclaration(VariableDeclaration? value) {
astVariable.variableDeclaration = value;
}
@@ -2049,6 +2053,7 @@ mixin DelegatingVariableMixin on InternalVariableMixin
return astVariable.accept1(v, arg);
}
// Coverage-ignore(suite): Not run.
String? get name => astVariable.cosmeticName;
// Coverage-ignore(suite): Not run.
@@ -2268,9 +2273,6 @@ mixin InternalVariableMixin on TreeNode implements InternalVariable {
@override
String? lateName;
@override
Variable get asVariableDeclaration => this as Variable;
}
/// Front end specific implementation of [LoadLibrary].
@@ -6022,7 +6024,7 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
VariableDeclaration? _variableForSideEffect;
/// The declared variable.
final VariableDeclaration variableDeclaration;
final InternalVariableDeclaration variableDeclaration;
new({required this.variableDeclaration, required this.error});
@@ -6033,20 +6035,13 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
required int forOffset,
required bool isClosureContextLoweringEnabled,
}) {
Variable loopVariable;
Variable loopVariable = variableDeclaration.variable.astVariable;
DartType loopVariableType;
bool checkAssignment = true;
if (variableDeclaration.variable case InternalVariable variable) {
loopVariable = variable.astVariable;
if (variable.isImplicitlyTyped) {
loopVariableType = variable.type = type;
checkAssignment = false;
} else {
loopVariableType = variable.type;
}
if (variableDeclaration.variable.isImplicitlyTyped) {
loopVariableType = variableDeclaration.variable.type = type;
checkAssignment = false;
} else {
// Coverage-ignore-block(suite): Not run.
loopVariable = variableDeclaration.variable;
loopVariableType = variableDeclaration.variable.type;
}
if (checkAssignment) {
@@ -6104,11 +6099,9 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.writeVariableInitialization(
variableDeclaration.variable,
variableDeclaration.variable.astVariable,
includeInitializer: false,
isImplicitlyTyped:
variableDeclaration.variable is InternalVariable &&
(variableDeclaration.variable as InternalVariable).isImplicitlyTyped,
isImplicitlyTyped: variableDeclaration.variable.isImplicitlyTyped,
);
}
@@ -6127,7 +6120,7 @@ class SingleVariableDeclarationForInElement extends _BaseForInElement {
/// `for (var a, b in [])`. This is an error case.
class MultiVariableDeclarationForInElement extends _BaseForInElement {
/// The declared variables.
final List<VariableDeclaration> variableDeclarations;
final List<InternalVariableDeclaration> variableDeclarations;
/// The error that should be emitted prior to the for-in statement.
final InvalidExpression error;
@@ -6138,21 +6131,18 @@ class MultiVariableDeclarationForInElement extends _BaseForInElement {
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
for (int i = 0; i < variableDeclarations.length; i++) {
VariableDeclaration variableDeclaration = variableDeclarations[i];
InternalVariableDeclaration variableDeclaration = variableDeclarations[i];
if (i == 0) {
printer.writeVariableInitialization(
variableDeclaration.variable,
variableDeclaration.variable.astVariable,
includeModifiersAndType: true,
includeInitializer: false,
isImplicitlyTyped:
variableDeclaration.variable is InternalVariable &&
(variableDeclaration.variable as InternalVariable)
.isImplicitlyTyped,
isImplicitlyTyped: variableDeclaration.variable.isImplicitlyTyped,
);
} else {
printer.write(', ');
printer.writeVariableInitialization(
variableDeclaration.variable,
variableDeclaration.variable.astVariable,
includeModifiersAndType: false,
includeInitializer: false,
);
@@ -6172,8 +6162,14 @@ class MultiVariableDeclarationForInElement extends _BaseForInElement {
return new ForInEncoding(
preLoopError: error,
bodyPrologue: extern.createBlock([
for (VariableDeclaration variableDeclaration in variableDeclarations)
extern.createVariableStatement(variableDeclaration),
for (InternalVariableDeclaration variableDeclaration
in variableDeclarations)
extern.createVariableStatement(
extern.createVariableDeclaration(
variableDeclaration.variable.astVariable,
fileOffset: variableDeclaration.fileOffset,
),
),
], fileOffset: TreeNode.noOffset),
);
}
@@ -8321,6 +8317,148 @@ class InternalCatch extends TreeNode with InternalTreeNode {
}
}
/// Declaration of a variable with an initial value.
class InternalVariableDeclaration extends TreeNode with InternalTreeNode {
/// The declared variable.
final InternalVariable variable;
new(this.variable) {
variable.parent = this;
}
@override
// Coverage-ignore(suite): Not run.
R accept<R>(TreeVisitor<R> v) {
unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
R accept1<R, A>(TreeVisitor1<R, A> v, A arg) {
unsupported("${runtimeType}.accept1 on ${v.runtimeType}", -1, null);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
variable.toTextInternal(printer);
}
@override
String toString() => 'InternalVariableDeclaration(${toStringInternal()}';
}
/// Declaration of a local variable.
class InternalVariableStatement extends InternalStatement {
/// The declared variable.
final InternalVariableDeclaration declaration;
new(this.declaration) {
declaration.parent = this;
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalVariableStatement(this);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
declaration.toTextInternal(printer);
printer.write(';');
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
class InternalForStatement extends InternalStatement implements LoopStatement {
// May be empty, but not null.
final List<InternalVariableDeclaration> variables;
final Expression? condition; // May be null.
final List<Expression> updates; // May be empty, but not null.
@override
Statement body;
new(this.variables, this.condition, this.updates, this.body) {
setParents(variables, this);
condition?.parent = this;
setParents(updates, this);
body.parent = this;
}
@override
StatementInferenceResult acceptInference(InferenceVisitorImpl visitor) {
return visitor.visitInternalForStatement(this);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('for (');
for (int index = 0; index < variables.length; index++) {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableInitialization(
variables[index].variable.astVariable,
includeModifiersAndType: index == 0,
);
}
printer.write('; ');
if (condition != null) {
printer.writeExpression(condition!);
}
printer.write('; ');
printer.writeExpressions(updates);
printer.write(') ');
printer.writeStatement(body);
}
@override
String toString() {
return "$runtimeType(${toStringInternal()})";
}
}
/// Synthetic expression of form `let v = x in y`
// TODO(johnniwinther): Can we avoid this?
class InternalLet extends InternalExpression {
final InternalVariable variable; // Must have an initializer.
final Expression body;
new(this.variable, this.body) {
variable.parent = this;
body.parent = this;
}
@override
ExpressionInferenceResult acceptInference(
InferenceVisitorImpl visitor,
DartType typeContext,
) {
return visitor.visitInternalLet(this, typeContext);
}
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
printer.write('let ');
printer.writeVariableInitialization(variable.astVariable);
printer.write(' in ');
printer.writeExpression(body);
}
@override
String toString() {
return "Let(${toStringInternal()})";
}
}
final InternalPattern dummyInternalPattern = new InternalConstantPattern(
expression: dummyExpression,
fileOffset: TreeNode.noOffset,
@@ -8362,3 +8500,6 @@ final InternalVariable dummyInternalVariable = new VariableDeclarationImpl(
fileOffset: TreeNode.noOffset,
isSynthesized: true,
);
final InternalVariableDeclaration dummyInternalVariableDeclaration =
new InternalVariableDeclaration(dummyInternalVariable);
@@ -129,7 +129,7 @@ Block createBlock(
Statement statement = statements[i];
if (statement is _VariablesDeclaration) {
copy ??= new List<Statement>.of(statements.getRange(0, i));
for (VariableDeclaration declaration in statement.declarations) {
for (InternalVariableDeclaration declaration in statement.declarations) {
copy.add(createVariableStatement(declaration));
}
} else if (copy != null) {
@@ -349,7 +349,7 @@ Statement createExpressionStatement(
ForElement createForElement(
int fileOffset,
List<VariableDeclaration> variables,
List<InternalVariableDeclaration> variables,
Expression? condition,
List<Expression> updates,
Expression body,
@@ -410,7 +410,7 @@ ForInStatement createForInStatement(
ForMapEntry createForMapEntry(
int fileOffset,
List<VariableDeclaration> variables,
List<InternalVariableDeclaration> variables,
Expression? condition,
List<Expression> updates,
MapLiteralEntry body,
@@ -422,12 +422,12 @@ ForMapEntry createForMapEntry(
/// Return a representation of a for statement.
Statement createForStatement(
int fileOffset,
List<VariableDeclaration>? variables,
List<InternalVariableDeclaration>? variables,
Expression? condition,
List<Expression> updaters,
Statement body,
) {
return new ForStatement(
return new InternalForStatement(
variables ?? // Coverage-ignore(suite): Not run.
[],
condition,
@@ -694,18 +694,18 @@ InternalVariable createLateVariable({
}
}
Let createLetForEffect({
InternalLet createLetForEffect({
required bool isClosureContextLoweringEnabled,
required Expression effect,
required DartType effectType,
required Expression expression,
}) {
return new Let(
return new InternalLet(
createSyntheticVariableForValue(
effect,
isClosureContextLoweringEnabled: isClosureContextLoweringEnabled,
type: effectType,
).asVariableDeclaration,
),
expression,
)..fileOffset = effect.fileOffset;
}
@@ -1099,8 +1099,8 @@ Expression createPatternAssignment(
PatternForElement createPatternForElement(
int fileOffset, {
required InternalPatternVariableDeclaration patternVariableDeclaration,
required List<VariableDeclaration> intermediateVariables,
required List<VariableDeclaration> variables,
required List<InternalVariableDeclaration> intermediateVariables,
required List<InternalVariableDeclaration> variables,
required Expression? condition,
required List<Expression> updates,
required Expression body,
@@ -1108,7 +1108,7 @@ PatternForElement createPatternForElement(
return new PatternForElement(
internalPatternVariableDeclaration: patternVariableDeclaration,
intermediateVariables: intermediateVariables,
variables: variables,
internalVariables: variables,
condition: condition,
updates: updates,
body: body,
@@ -1118,8 +1118,8 @@ PatternForElement createPatternForElement(
PatternForMapEntry createPatternForMapEntry(
int fileOffset, {
required InternalPatternVariableDeclaration patternVariableDeclaration,
required List<VariableDeclaration> intermediateVariables,
required List<VariableDeclaration> variableInitializations,
required List<InternalVariableDeclaration> intermediateVariables,
required List<InternalVariableDeclaration> variableInitializations,
required Expression? condition,
required List<Expression> updates,
required MapLiteralEntry body,
@@ -1127,7 +1127,7 @@ PatternForMapEntry createPatternForMapEntry(
return new PatternForMapEntry(
internalPatternVariableDeclaration: patternVariableDeclaration,
intermediateVariables: intermediateVariables,
variables: variableInitializations,
internalVariables: variableInitializations,
condition: condition,
updates: updates,
body: body,
@@ -1620,11 +1620,11 @@ UnaryExpression createUnary(
return new UnaryExpression(unaryName, expression)..fileOffset = fileOffset;
}
VariableDeclaration createVariableDeclaration(
InternalVariableDeclaration createVariableDeclaration(
InternalVariable variable, {
int? fileOffset,
}) {
return new VariableDeclaration(variable.asVariableDeclaration)
return new InternalVariableDeclaration(variable)
..fileOffset = fileOffset ?? variable.fileOffset;
}
@@ -1655,11 +1655,11 @@ InternalVariableSet createVariableSet(
return new InternalVariableSet(variable, value)..fileOffset = fileOffset;
}
VariableStatement createVariableStatement(
VariableDeclaration declaration, {
InternalVariableStatement createVariableStatement(
InternalVariableDeclaration declaration, {
int? fileOffset,
}) {
return new VariableStatement(declaration)
return new InternalVariableStatement(declaration)
..fileOffset = fileOffset ?? declaration.fileOffset;
}
@@ -1714,13 +1714,13 @@ bool isThisExpression(Object node) =>
bool isVariablesDeclaration(Object? node) => node is _VariablesDeclaration;
_VariablesDeclaration variablesDeclaration(
List<VariableDeclaration> declarations,
List<InternalVariableDeclaration> declarations,
Uri uri,
) {
return new _VariablesDeclaration(declarations, uri);
}
List<VariableDeclaration> variablesDeclarationExtractDeclarations(
List<InternalVariableDeclaration> variablesDeclarationExtractDeclarations(
Object? variablesDeclaration,
) {
return (variablesDeclaration as _VariablesDeclaration).declarations;
@@ -1735,7 +1735,7 @@ Statement wrapVariables(Statement statement) {
growable: true,
),
)..fileOffset = statement.fileOffset;
} else if (statement is VariableStatement) {
} else if (statement is InternalVariableStatement) {
return new Block(<Statement>[statement])..fileOffset = statement.fileOffset;
} else {
return statement;
@@ -1743,7 +1743,7 @@ Statement wrapVariables(Statement statement) {
}
class _VariablesDeclaration extends AuxiliaryStatement {
final List<VariableDeclaration> declarations;
final List<InternalVariableDeclaration> declarations;
final Uri uri;
new(this.declarations, this.uri) {
@@ -1774,8 +1774,8 @@ class _VariablesDeclaration extends AuxiliaryStatement {
if (index > 0) {
printer.write(', ');
}
printer.writeVariableDeclaration(
declarations[index],
printer.writeVariableInitialization(
declarations[index].variable.astVariable,
includeModifiersAndType: index == 0,
);
}
@@ -95,8 +95,9 @@ class MultipleStatementInferenceResult implements StatementInferenceResult {
int get statementCount => statements.length;
}
class VariableDeclarationInferenceResult {
const new();
sealed class VariableDeclarationInferenceResult {
factory direct(VariableDeclaration declaration) =
DirectVariableDeclarationInferenceResult;
factory effect([Expression? expression]) =
EffectVariableDeclarationInferenceResult;
@@ -107,10 +108,23 @@ class VariableDeclarationInferenceResult {
required int fileOffset,
}) = LateVariableDeclarationInferenceResult;
bool get hasChanged => false;
StatementInferenceResult toStatementInferenceResult({
required int fileOffset,
});
}
StatementInferenceResult toStatementInferenceResult() =>
const StatementInferenceResult();
class DirectVariableDeclarationInferenceResult
implements VariableDeclarationInferenceResult {
final VariableDeclaration declaration;
new(this.declaration);
@override
StatementInferenceResult toStatementInferenceResult({
required int fileOffset,
}) => new StatementInferenceResult.single(
createVariableStatement(declaration, fileOffset: fileOffset),
);
}
class EffectVariableDeclarationInferenceResult
@@ -120,16 +134,13 @@ class EffectVariableDeclarationInferenceResult
new([this.expression]);
@override
// Coverage-ignore(suite): Not run.
bool get hasChanged => true;
@override
StatementInferenceResult toStatementInferenceResult() =>
new StatementInferenceResult.single(
expression != null
? createExpressionStatement(expression!)
: createEmptyStatement(),
);
StatementInferenceResult toStatementInferenceResult({
required int fileOffset,
}) => new StatementInferenceResult.single(
expression != null
? createExpressionStatement(expression!, fileOffset: fileOffset)
: createEmptyStatement(fileOffset: fileOffset),
);
}
class LateVariableDeclarationInferenceResult
@@ -145,16 +156,13 @@ class LateVariableDeclarationInferenceResult
});
@override
// Coverage-ignore(suite): Not run.
bool get hasChanged => true;
@override
StatementInferenceResult toStatementInferenceResult() =>
new StatementInferenceResult.multiple(fileOffset, [
for (VariableDeclaration variableDeclaration in variableDeclarations)
createVariableStatement(variableDeclaration),
...functionDeclarations,
]);
StatementInferenceResult toStatementInferenceResult({
required int fileOffset,
}) => new StatementInferenceResult.multiple(fileOffset, [
for (VariableDeclaration variableDeclaration in variableDeclarations)
createVariableStatement(variableDeclaration),
...functionDeclarations,
]);
}
/// Tells the inferred type and how the code should be transformed.
@@ -2626,7 +2626,6 @@ class InferenceVisitorImpl extends InferenceVisitorBase
flowAnalysis.doStatement_bodyBegin(node);
StatementInferenceResult bodyResult = inferStatement(node.body);
if (bodyResult.hasChanged) {
// Coverage-ignore-block(suite): Not run.
node.body = bodyResult.statement..parent = node;
}
flowAnalysis.doStatement_conditionBegin();
@@ -3452,17 +3451,29 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
@override
// Coverage-ignore(suite): Not run.
StatementInferenceResult visitForStatement(ForStatement node) {
_unhandledStatement(node);
}
StatementInferenceResult visitInternalForStatement(
InternalForStatement node,
) {
ScopeProviderInfo? scopeProviderInfo;
if (isClosureContextLoweringEnabled) {
scopeProviderInfo = _contextAllocationStrategy.enterScopeProvider(
scopeProviderInfoKind: ScopeProviderInfoKind.Loop,
);
}
List<VariableDeclaration> variables = new List.filled(
node.variables.length,
dummyVariableDeclaration,
growable: true,
);
for (int index = 0; index < node.variables.length; index++) {
VariableDeclaration variableDeclaration = node.variables[index];
Variable variable = variableDeclaration.variable;
if (variable.name == null) {
InternalVariableDeclaration variableDeclaration = node.variables[index];
InternalVariable variable = variableDeclaration.variable;
if (variable.cosmeticName == null) {
if (variable.initializer != null) {
ExpressionInferenceResult result = inferExpression(
variable.initializer!,
@@ -3472,16 +3483,27 @@ class InferenceVisitorImpl extends InferenceVisitorBase
variable.initializer = result.expression..parent = variable;
variable.type = result.inferredType;
}
variables[index] = extern.createVariableDeclaration(
variable.astVariable,
fileOffset: variableDeclaration.fileOffset,
);
} else {
VariableDeclarationInferenceResult variableResult =
inferVariableDeclaration(variableDeclaration);
assert(
!variableResult.hasChanged,
"Unexpected variable declaration change.",
);
switch (variableResult) {
case DirectVariableDeclarationInferenceResult():
variables[index] = variableResult.declaration;
// Coverage-ignore(suite): Not run.
case EffectVariableDeclarationInferenceResult():
case LateVariableDeclarationInferenceResult():
throw new UnsupportedError(
"Unexpected variable declaration change.",
);
}
}
}
flowAnalysis.for_conditionBegin(node);
Expression? condition;
if (node.condition != null) {
InterfaceType expectedType = coreTypes.boolRawType(
Nullability.nonNullable,
@@ -3491,36 +3513,51 @@ class InferenceVisitorImpl extends InferenceVisitorBase
expectedType,
isVoidAllowed: true,
);
Expression condition = ensureAssignableResult(
condition = ensureAssignableResult(
expectedType,
conditionResult,
).expression;
node.condition = condition..parent = node;
}
flowAnalysis.for_bodyBegin(node, switch (node.condition) {
flowAnalysis.for_bodyBegin(node, switch (condition) {
null => flowAnalysis.booleanLiteral(true),
var condition => flowAnalysis.getExpressionInfo(condition),
});
StatementInferenceResult bodyResult = inferStatement(node.body);
if (bodyResult.hasChanged) {
node.body = bodyResult.statement..parent = node;
}
Statement body = bodyResult.hasChanged ? bodyResult.statement : node.body;
flowAnalysis.for_updaterBegin();
List<Expression> updates = new List.filled(
node.updates.length,
dummyExpression,
growable: true,
);
for (int index = 0; index < node.updates.length; index++) {
ExpressionInferenceResult updateResult = inferExpression(
node.updates[index],
const UnknownType(),
isVoidAllowed: true,
);
node.updates[index] = updateResult.expression..parent = node;
updates[index] = updateResult.expression;
}
flowAnalysis.for_end();
Scope? scope;
if (scopeProviderInfo != null) {
_contextAllocationStrategy.exitScopeProvider(scopeProviderInfo);
node.scope = scopeProviderInfo.scope;
scope = scopeProviderInfo.scope;
}
return const StatementInferenceResult();
Statement replacement = extern.createForStatement(
variables: variables,
condition: condition,
updates: updates,
body: body,
scope: scope,
fileOffset: node.fileOffset,
);
libraryBuilder.loader.dataForTesting
// Coverage-ignore(suite): Not run.
?.registerAlias(node, replacement);
return new StatementInferenceResult.single(replacement);
}
LocalFunctionResult _visitInternalFunctionNode(
@@ -4410,11 +4447,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<Variable> declaredVariables = pattern.declaredVariables;
assert(declaredVariables.length == element.intermediateVariables.length);
assert(declaredVariables.length == element.variables.length);
assert(declaredVariables.length == element.internalVariables.length);
for (int i = 0; i < declaredVariables.length; i++) {
DartType type = declaredVariables[i].type;
Variable intermediateVariable = element.intermediateVariables[i].variable;
Variable intermediateVariable =
element.intermediateVariables[i].variable.astVariable;
intermediateVariable.initializer = inferExpression(
intermediateVariable.initializer!,
type,
@@ -4422,7 +4460,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
).expression..parent = intermediateVariable;
intermediateVariable.type = type;
element.variables[i].variable.type = type;
element.internalVariables[i].variable.type = type;
}
return _inferForElementBase(
@@ -4453,10 +4491,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase
Map<TreeNode, DartType> inferredSpreadTypes,
Map<Expression, DartType> inferredConditionTypes,
) {
for (int index = 0; index < element.variables.length; index++) {
VariableDeclaration variableDeclaration = element.variables[index];
Variable variable = variableDeclaration.variable;
if (variable.name == null) {
List<VariableDeclaration> variables = new List.filled(
element.internalVariables.length,
dummyVariableDeclaration,
growable: true,
);
for (int index = 0; index < element.internalVariables.length; index++) {
InternalVariableDeclaration variableDeclaration =
element.internalVariables[index];
InternalVariable variable = variableDeclaration.variable;
if (variable.cosmeticName == null) {
if (variable.initializer != null) {
ExpressionInferenceResult initializerResult = inferExpression(
variable.initializer!,
@@ -4467,15 +4511,26 @@ class InferenceVisitorImpl extends InferenceVisitorBase
..parent = variable;
variable.type = initializerResult.inferredType;
}
variables[index] = extern.createVariableDeclaration(
variable.astVariable,
fileOffset: variableDeclaration.fileOffset,
);
} else {
VariableDeclarationInferenceResult variableResult =
inferVariableDeclaration(variableDeclaration);
assert(
!variableResult.hasChanged,
"Unexpected variable declaration change.",
);
switch (variableResult) {
case DirectVariableDeclarationInferenceResult():
variables[index] = variableResult.declaration;
// Coverage-ignore(suite): Not run.
case EffectVariableDeclarationInferenceResult():
case LateVariableDeclarationInferenceResult():
throw new UnsupportedError(
"Unexpected variable declaration change.",
);
}
}
}
element.variables = variables;
flowAnalysis.for_conditionBegin(element);
if (element.condition != null) {
@@ -5353,9 +5408,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// Coverage-ignore(suite): Not run.
?.registerAlias(element, loop);
body.add(element.patternVariableDeclaration);
for (VariableDeclaration intermediateVariable
for (InternalVariableDeclaration intermediateVariable
in element.intermediateVariables) {
body.add(extern.createVariableStatement(intermediateVariable));
body.add(
extern.createVariableStatement(
extern.createVariableDeclaration(
intermediateVariable.variable.astVariable,
fileOffset: intermediateVariable.fileOffset,
),
),
);
}
body.add(loop);
}
@@ -5390,7 +5452,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: _createBlock(statements);
Statement loop = _createForInStatement(
node.fileOffset,
node.variable!,
node.variable,
node.iterable,
loopBody,
isAsync: node.isAsync,
@@ -5976,9 +6038,16 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// Coverage-ignore(suite): Not run.
?.registerAlias(entry, loop);
body.add(entry.patternVariableDeclaration);
for (VariableDeclaration intermediateVariable
for (InternalVariableDeclaration intermediateVariable
in entry.intermediateVariables) {
body.add(extern.createVariableStatement(intermediateVariable));
body.add(
extern.createVariableStatement(
extern.createVariableDeclaration(
intermediateVariable.variable.astVariable,
fileOffset: intermediateVariable.fileOffset,
),
),
);
}
body.add(loop);
}
@@ -6013,7 +6082,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: _createBlock(statements);
Statement loop = _createForInStatement(
node.fileOffset,
node.variable!,
node.variable,
node.iterable,
loopBody,
isAsync: node.isAsync,
@@ -7551,11 +7620,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<Variable> declaredVariables = pattern.declaredVariables;
assert(declaredVariables.length == entry.intermediateVariables.length);
assert(declaredVariables.length == entry.variables.length);
assert(declaredVariables.length == entry.internalVariables.length);
for (int i = 0; i < declaredVariables.length; i++) {
DartType type = declaredVariables[i].type;
Variable intermediateVariable = entry.intermediateVariables[i].variable;
InternalVariable intermediateVariable =
entry.intermediateVariables[i].variable;
intermediateVariable.initializer = inferExpression(
intermediateVariable.initializer!,
type,
@@ -7563,7 +7633,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
).expression..parent = intermediateVariable;
intermediateVariable.type = type;
entry.variables[i].variable.type = type;
entry.internalVariables[i].variable.type = type;
}
return _inferForMapEntryBase(
@@ -7618,10 +7688,17 @@ class InferenceVisitorImpl extends InferenceVisitorBase
Map<Expression, DartType> inferredConditionTypes,
_MapLiteralEntryOffsets offsets,
) {
for (int index = 0; index < entry.variables.length; index++) {
VariableDeclaration variableDeclaration = entry.variables[index];
Variable variable = variableDeclaration.variable;
if (variable.name == null) {
List<VariableDeclaration> variables = new List.filled(
entry.internalVariables.length,
dummyVariableDeclaration,
growable: true,
);
for (int index = 0; index < entry.internalVariables.length; index++) {
InternalVariableDeclaration variableDeclaration =
entry.internalVariables[index];
Variable variable = variableDeclaration.variable.astVariable;
if (variable.cosmeticName == null) {
if (variable.initializer != null) {
ExpressionInferenceResult result = inferExpression(
variable.initializer!,
@@ -7631,15 +7708,23 @@ class InferenceVisitorImpl extends InferenceVisitorBase
variable.initializer = result.expression..parent = variable;
variable.type = result.inferredType;
}
variables[index] = createVariableDeclaration(variable);
} else {
VariableDeclarationInferenceResult variableResult =
inferVariableDeclaration(variableDeclaration);
assert(
!variableResult.hasChanged,
"Unexpected variable declaration change.",
);
switch (variableResult) {
case DirectVariableDeclarationInferenceResult():
variables[index] = variableResult.declaration;
// Coverage-ignore(suite): Not run.
case EffectVariableDeclarationInferenceResult():
case LateVariableDeclarationInferenceResult():
throw new UnsupportedError(
"Unexpected variable declaration change.",
);
}
}
}
entry.variables = variables;
flowAnalysis.for_conditionBegin(entry);
if (entry.condition != null) {
@@ -8395,22 +8480,26 @@ class InferenceVisitorImpl extends InferenceVisitorBase
internalPatternVariableDeclaration:
entry.internalPatternVariableDeclaration,
intermediateVariables: entry.intermediateVariables,
variables: entry.variables,
internalVariables: entry.internalVariables,
condition: entry.condition,
updates: entry.updates,
body: convertToElement(entry.body, onConvertMapEntry),
)
..patternVariableDeclaration = entry.patternVariableDeclaration
..variables = entry.variables
..fileOffset = entry.fileOffset;
onConvertMapEntry(entry, result);
return result;
case ForMapEntry():
ForElement result = new ForElement(
entry.variables,
entry.condition,
entry.updates,
convertToElement(entry.body, onConvertMapEntry),
)..fileOffset = entry.fileOffset;
ForElement result =
new ForElement(
entry.internalVariables,
entry.condition,
entry.updates,
convertToElement(entry.body, onConvertMapEntry),
)
..variables = entry.variables
..fileOffset = entry.fileOffset;
onConvertMapEntry(entry, result);
return result;
case ForInMapEntry():
@@ -8421,9 +8510,8 @@ class InferenceVisitorImpl extends InferenceVisitorBase
isAsync: entry.isAsync,
fileOffset: entry.fileOffset,
forOffset: entry.forOffset,
variable: entry.variable,
encoding: entry.encoding,
);
)..variable = entry.variable;
onConvertMapEntry(entry, result);
return result;
}
@@ -11808,23 +11896,34 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
@override
// Coverage-ignore(suite): Not run.
ExpressionInferenceResult visitLet(Let node, DartType typeContext) {
_unhandledExpression(node, typeContext);
}
ExpressionInferenceResult visitInternalLet(
InternalLet node,
DartType typeContext,
) {
DartType variableType = node.variable.type;
ExpressionInferenceResult initializerResult = inferExpression(
node.variable.initializer!,
variableType,
isVoidAllowed: true,
);
node.variable.initializer = initializerResult.expression
..parent = node.variable;
Variable variable = node.variable.astVariable;
variable.initializer = initializerResult.expression..parent = variable;
ExpressionInferenceResult bodyResult = inferExpression(
node.body,
typeContext,
isVoidAllowed: true,
);
node.body = bodyResult.expression..parent = node;
Expression body = bodyResult.expression..parent = node;
DartType inferredType = bodyResult.inferredType;
return new ExpressionInferenceResult(inferredType, node);
return new ExpressionInferenceResult(
inferredType,
extern.createLet(variable, body, fileOffset: node.fileOffset),
);
}
ExpressionInferenceResult visitAnonymousMethodExpression(
@@ -13154,6 +13253,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<SwitchExpressionCase> cases = new List.filled(
node.cases.length,
dummySwitchExpressionCase,
growable: true,
);
for (int i = node.cases.length - 1; i >= 0; i--) {
cases[i] = popRewrite() as SwitchExpressionCase;
@@ -13357,6 +13457,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<PatternSwitchCase> cases = new List.filled(
node.cases.length,
dummyPatternSwitchCase,
growable: true,
);
for (int i = node.cases.length - 1; i >= 0; i--) {
cases[i] = popRewrite() as PatternSwitchCase;
@@ -13547,11 +13648,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
}
StatementInferenceResult bodyResult = inferStatement(node.body);
Statement body = bodyResult.hasChanged
?
// Coverage-ignore(suite): Not run.
bodyResult.statement
: node.body;
Statement body = bodyResult.hasChanged ? bodyResult.statement : node.body;
Scope? scope;
if (scopeProviderInfo != null) {
_contextAllocationStrategy.exitScopeProvider(scopeProviderInfo);
@@ -13618,9 +13715,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
result = new TryFinally(
result,
finalizerResult!.hasChanged
?
// Coverage-ignore(suite): Not run.
finalizerResult.statement
? finalizerResult.statement
: node.finallyBlock!,
)..fileOffset = node.fileOffset;
}
@@ -13689,30 +13784,31 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
VariableDeclarationInferenceResult inferVariableDeclaration(
VariableDeclaration node,
InternalVariableDeclaration node,
) {
InternalVariable nodeVariable = node.variable as InternalVariable;
VariableDeclarationInferenceResult variableDeclarationInferenceResult =
_inferInternalExpressionVariableDeclaration(
node,
node.variable,
nodeVariable,
);
node.variable = nodeVariable.astVariable;
_inferInternalExpressionVariableDeclaration(node, node.variable);
if (isClosureContextLoweringEnabled) {
_contextAllocationStrategy.handleDeclarationOfVariable(
node.variable,
captureKind: _captureKindForVariable(node.variable),
node.variable.astVariable,
captureKind: _captureKindForVariable(node.variable.astVariable),
);
}
return variableDeclarationInferenceResult;
}
@override
// Coverage-ignore(suite): Not run.
StatementInferenceResult visitVariableStatement(VariableStatement node) {
_unhandledStatement(node);
}
StatementInferenceResult visitInternalVariableStatement(
InternalVariableStatement node,
) {
return inferVariableDeclaration(
node.declaration,
).toStatementInferenceResult();
).toStatementInferenceResult(fileOffset: node.fileOffset);
}
@override
@@ -14607,6 +14703,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<Expression> expressions = new List.filled(
case_.expressions.length,
dummyExpression,
growable: true,
);
for (int i = case_.expressions.length - 1; i >= 0; i--) {
expressions[i] = popRewrite() as Expression; // CaseHead
@@ -14688,6 +14785,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<PatternGuard> patternGuards = new List.filled(
case_.patternGuards.length,
dummyPatternGuard,
growable: true,
);
for (int i = case_.patternGuards.length - 1; i >= 0; i--) {
patternGuards[i] = popRewrite() as PatternGuard;
@@ -15416,6 +15514,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<Pattern> patterns = new List.filled(
node.patterns.length,
dummyPattern,
growable: true,
);
for (int i = node.patterns.length - 1; i >= 0; i--) {
Object? rewrite = popRewrite();
@@ -15655,6 +15754,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<NamedPattern> fields = new List.filled(
node.fields.length,
dummyNamedPattern,
growable: true,
);
for (int i = node.fields.length - 1; i >= 0; i--) {
InternalNamedPattern field = node.fields[i];
@@ -16232,6 +16332,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
List<Pattern> patterns = new List.filled(
node.patterns.length,
dummyPattern,
growable: true,
);
for (int i = node.patterns.length - 1; i >= 0; i--) {
InternalPattern subPattern = node.patterns[i];
@@ -17296,13 +17397,12 @@ class InferenceVisitorImpl extends InferenceVisitorBase
VariableDeclarationInferenceResult
_inferInternalExpressionVariableDeclaration(
VariableDeclaration variableDeclaration,
Variable node,
InternalVariable nodeVariable,
InternalVariableDeclaration variableDeclaration,
InternalVariable internalVariable,
) {
DartType declaredType = nodeVariable.isImplicitlyTyped
DartType declaredType = internalVariable.isImplicitlyTyped
? const UnknownType()
: node.type;
: internalVariable.type;
DartType inferredType;
ExpressionInferenceResult? initializerResult;
@@ -17310,10 +17410,11 @@ class InferenceVisitorImpl extends InferenceVisitorBase
// for loops, const variables, and late variables. This logic turns them
// into `ExpressionStatement`s or `EmptyStatement`s so the backends don't
// need to allocate space for them.
if (node.isWildcard &&
!node.isConst &&
node.parent?.parent is! ForStatement) {
if (node.initializer case var initializer? when !node.isLate) {
if (internalVariable.isWildcard &&
!internalVariable.isConst &&
internalVariable.parent?.parent is! InternalForStatement) {
if (internalVariable.initializer case var initializer?
when !internalVariable.isLate) {
return new VariableDeclarationInferenceResult.effect(
inferExpression(
initializer,
@@ -17325,88 +17426,97 @@ class InferenceVisitorImpl extends InferenceVisitorBase
return new VariableDeclarationInferenceResult.effect();
}
}
if (node.initializer != null) {
if (node.isLate && node.hasDeclaredInitializer) {
List<VariableContext>? capturedContexts;
if (internalVariable.initializer != null) {
if (internalVariable.isLate && internalVariable.hasDeclaredInitializer) {
// TODO(62401): Remove the cast when the flow analysis uses
// [InternalExpressionVariable]s.
Variable variable = (node.variable as InternalVariable).astVariable;
if (isClosureContextLoweringEnabled) {
node.capturedContexts = _contextAllocationStrategy
capturedContexts = _contextAllocationStrategy
.computeCapturedVariableContexts(
_capturedVariablesForNode(variable),
_capturedVariablesForNode(internalVariable.astVariable),
);
}
flowAnalysis.lateInitializer_begin(variable);
flowAnalysis.lateInitializer_begin(internalVariable.astVariable);
}
initializerResult = inferExpression(
node.initializer!,
internalVariable.initializer!,
declaredType,
isVoidAllowed: true,
);
if (node.isLate && node.hasDeclaredInitializer) {
if (internalVariable.isLate && internalVariable.hasDeclaredInitializer) {
flowAnalysis.lateInitializer_end();
}
inferredType = inferDeclarationType(
initializerResult.inferredType,
forSyntheticVariable: node.name == null,
forSyntheticVariable: internalVariable.cosmeticName == null,
inferenceDefaultType: InferenceDefaultType.Dynamic,
);
} else {
inferredType = const DynamicType();
}
if (nodeVariable.isImplicitlyTyped) {
if (internalVariable.isImplicitlyTyped) {
if (dataForTesting != null) {
// Coverage-ignore-block(suite): Not run.
dataForTesting!.typeInferenceResult.inferredVariableTypes[node] =
dataForTesting!
.typeInferenceResult
.inferredVariableTypes[internalVariable] =
inferredType;
}
node.type = inferredType;
internalVariable.type = inferredType;
}
flowAnalysis.declare(
nodeVariable.astVariable,
new SharedTypeView(node.type),
initialized: node.hasDeclaredInitializer,
internalVariable.astVariable,
new SharedTypeView(internalVariable.type),
initialized: internalVariable.hasDeclaredInitializer,
);
if (initializerResult != null) {
DartType initializerType = initializerResult.inferredType;
flowAnalysis.initialize(
nodeVariable.astVariable,
internalVariable.astVariable,
new SharedTypeView(initializerType),
flowAnalysis.getExpressionInfo(initializerResult.expression),
isFinal: node.isFinal,
isLate: node.isLate,
isImplicitlyTyped: nodeVariable.isImplicitlyTyped,
isFinal: internalVariable.isFinal,
isLate: internalVariable.isLate,
isImplicitlyTyped: internalVariable.isImplicitlyTyped,
);
initializerResult = ensureAssignableResult(
node.type,
internalVariable.type,
initializerResult,
fileOffset: node.fileOffset,
isVoidAllowed: node.type is VoidType,
fileOffset: internalVariable.fileOffset,
isVoidAllowed: internalVariable.type is VoidType,
);
Expression initializer = initializerResult.expression;
node.initializer = initializer..parent = node;
internalVariable.initializer = initializer..parent = internalVariable;
}
if (node.isLate &&
if (internalVariable.isLate &&
libraryBuilder.loader.target.backendTarget.isLateLocalLoweringEnabled(
hasInitializer: node.hasDeclaredInitializer,
isFinal: node.isFinal,
isPotentiallyNullable: node.type.isPotentiallyNullable,
hasInitializer: internalVariable.hasDeclaredInitializer,
isFinal: internalVariable.isFinal,
isPotentiallyNullable: internalVariable.type.isPotentiallyNullable,
)) {
int fileOffset = node.fileOffset;
int fileOffset = internalVariable.fileOffset;
List<VariableDeclaration> variableDeclarations = [];
List<FunctionDeclaration> functionDeclarations = [];
variableDeclarations.add(variableDeclaration);
variableDeclarations.add(
extern.createVariableDeclaration(
internalVariable.astVariable,
fileOffset: variableDeclaration.fileOffset,
),
);
late_lowering.IsSetEncoding isSetEncoding = late_lowering
.computeIsSetEncoding(
node.type,
internalVariable.type,
late_lowering.computeIsSetStrategy(libraryBuilder),
);
Variable? isSetVariable;
if (isSetEncoding == late_lowering.IsSetEncoding.useIsSetField) {
isSetVariable = new Variable(
late_lowering.computeLateLocalIsSetName(node.name!),
late_lowering.computeLateLocalIsSetName(
internalVariable.cosmeticName!,
),
initializer: new BoolLiteral(false)..fileOffset = fileOffset,
type: coreTypes.boolRawType(Nullability.nonNullable),
isLowered: true,
@@ -17418,45 +17528,50 @@ class InferenceVisitorImpl extends InferenceVisitorBase
Expression createVariableRead({bool needsPromotion = false}) {
if (needsPromotion) {
return new VariableGet(node.variable, node.type)
..fileOffset = fileOffset;
return new VariableGet(
internalVariable.variable,
internalVariable.type,
)..fileOffset = fileOffset;
} else {
return new VariableGet(node.variable)..fileOffset = fileOffset;
return new VariableGet(internalVariable.variable)
..fileOffset = fileOffset;
}
}
Expression createIsSetRead() =>
new VariableGet(isSetVariable!)..fileOffset = fileOffset;
Expression createVariableWrite(Expression value) =>
new VariableSet(node.variable, value);
new VariableSet(internalVariable.variable, value);
Expression createIsSetWrite(Expression value) =>
new VariableSet(isSetVariable!, value);
Variable getVariable = new Variable(
late_lowering.computeLateLocalGetterName(node.name!),
late_lowering.computeLateLocalGetterName(
internalVariable.cosmeticName!,
),
isLowered: true,
)..fileOffset = fileOffset;
FunctionDeclaration getter = new FunctionDeclaration(
getVariable,
new FunctionNode(
node.initializer == null
internalVariable.initializer == null
? late_lowering.createGetterBodyWithoutInitializer(
coreTypes,
fileOffset,
node.name!,
node.type,
internalVariable.cosmeticName!,
internalVariable.type,
createVariableRead: createVariableRead,
createIsSetRead: createIsSetRead,
isSetEncoding: isSetEncoding,
forField: false,
)
: (node.isFinal
: (internalVariable.isFinal
? late_lowering.createGetterWithInitializerWithRecheck(
coreTypes,
fileOffset,
node.name!,
node.type,
node.initializer!,
internalVariable.cosmeticName!,
internalVariable.type,
internalVariable.initializer!,
createVariableRead: createVariableRead,
createVariableWrite: createVariableWrite,
createIsSetRead: createIsSetRead,
@@ -17467,45 +17582,47 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: late_lowering.createGetterWithInitializer(
coreTypes,
fileOffset,
node.name!,
node.type,
node.initializer!,
internalVariable.cosmeticName!,
internalVariable.type,
internalVariable.initializer!,
createVariableRead: createVariableRead,
createVariableWrite: createVariableWrite,
createIsSetRead: createIsSetRead,
createIsSetWrite: createIsSetWrite,
isSetEncoding: isSetEncoding,
)),
returnType: node.type,
),
returnType: internalVariable.type,
)..capturedContexts = capturedContexts,
)..fileOffset = fileOffset;
getVariable.type = getter.function.computeFunctionType(
Nullability.nonNullable,
);
nodeVariable.lateGetter = getVariable;
internalVariable.lateGetter = getVariable;
functionDeclarations.add(getter);
if (!node.isFinal || node.initializer == null) {
nodeVariable.isLateFinalWithoutInitializer =
node.isFinal && node.initializer == null;
if (!internalVariable.isFinal || internalVariable.initializer == null) {
internalVariable.isLateFinalWithoutInitializer =
internalVariable.isFinal && internalVariable.initializer == null;
Variable setVariable = new Variable(
late_lowering.computeLateLocalSetterName(node.name!),
late_lowering.computeLateLocalSetterName(
internalVariable.cosmeticName!,
),
isLowered: true,
)..fileOffset = fileOffset;
Variable setterParameter = new Variable(
"${node.name}#param",
type: node.type,
"${internalVariable.cosmeticName}#param",
type: internalVariable.type,
)..fileOffset = fileOffset;
FunctionDeclaration setter = new FunctionDeclaration(
setVariable,
new FunctionNode(
node.isFinal
internalVariable.isFinal
? late_lowering.createSetterBodyFinal(
coreTypes,
fileOffset,
node.name!,
internalVariable.cosmeticName!,
setterParameter,
node.type,
internalVariable.type,
shouldReturnValue: true,
createVariableRead: createVariableRead,
createVariableWrite: createVariableWrite,
@@ -17517,9 +17634,9 @@ class InferenceVisitorImpl extends InferenceVisitorBase
: late_lowering.createSetterBody(
coreTypes,
fileOffset,
node.name!,
internalVariable.cosmeticName!,
setterParameter,
node.type,
internalVariable.type,
shouldReturnValue: true,
createVariableWrite: createVariableWrite,
createIsSetWrite: createIsSetWrite,
@@ -17535,34 +17652,43 @@ class InferenceVisitorImpl extends InferenceVisitorBase
setVariable.type = setter.function.computeFunctionType(
Nullability.nonNullable,
);
nodeVariable.lateSetter = setVariable;
internalVariable.lateSetter = setVariable;
functionDeclarations.add(setter);
}
node.isLate = false;
nodeVariable.lateType = node.type;
internalVariable.isLate = false;
internalVariable.lateType = internalVariable.type;
if (isSetEncoding == late_lowering.IsSetEncoding.useSentinel) {
node.initializer =
internalVariable.initializer =
new StaticInvocation(
coreTypes.createSentinelMethod,
new Arguments([], types: [node.type])..fileOffset = fileOffset,
new Arguments([], types: [internalVariable.type])
..fileOffset = fileOffset,
)
..fileOffset = fileOffset
..parent = node;
..parent = internalVariable;
} else {
node.initializer = null;
internalVariable.initializer = null;
}
node.type = computeNullable(node.type);
nodeVariable.lateName = node.name;
node.isLowered = true;
node.name = late_lowering.computeLateLocalName(node.name!);
internalVariable.type = computeNullable(internalVariable.type);
internalVariable.lateName = internalVariable.cosmeticName;
internalVariable.isLowered = true;
internalVariable.cosmeticName = late_lowering.computeLateLocalName(
internalVariable.cosmeticName!,
);
return new VariableDeclarationInferenceResult.late(
variableDeclarations,
functionDeclarations,
fileOffset: node.fileOffset,
fileOffset: internalVariable.fileOffset,
);
}
return const VariableDeclarationInferenceResult();
return new VariableDeclarationInferenceResult.direct(
extern.createVariableDeclaration(
internalVariable.astVariable,
capturedContexts: capturedContexts,
fileOffset: variableDeclaration.fileOffset,
),
);
}
@override
@@ -225,17 +225,31 @@ void main() {
void _testVariableDeclarations() {
testStatement(
forest.variablesDeclaration([
new VariableDeclaration(new Variable('a')),
new VariableDeclaration(new Variable('b')),
new InternalVariableDeclaration(
new VariableDeclarationImpl('a', fileOffset: TreeNode.noOffset),
),
new InternalVariableDeclaration(
new VariableDeclarationImpl('b', fileOffset: TreeNode.noOffset),
),
], dummyUri),
'''
dynamic a, b;''',
);
testStatement(
forest.variablesDeclaration([
new VariableDeclaration(new Variable('a', type: const VoidType())),
new VariableDeclaration(
new Variable('b', initializer: new NullLiteral()),
new InternalVariableDeclaration(
new VariableDeclarationImpl(
'a',
type: const VoidType(),
fileOffset: TreeNode.noOffset,
),
),
new InternalVariableDeclaration(
new VariableDeclarationImpl(
'b',
initializer: new NullLiteral(),
fileOffset: TreeNode.noOffset,
),
),
], dummyUri),
'''
@@ -378,7 +392,7 @@ void _testInternalForInStatement() {
testStatement(
new InternalForInStatement(
new SingleVariableDeclarationForInElement(
variableDeclaration: new VariableDeclaration(
variableDeclaration: new InternalVariableDeclaration(
new VariableDeclarationImpl('e', fileOffset: -1),
),
error: null,
@@ -396,7 +410,7 @@ for (var e in null) {}''',
testStatement(
new InternalForInStatement(
new SingleVariableDeclarationForInElement(
variableDeclaration: new VariableDeclaration(
variableDeclaration: new InternalVariableDeclaration(
new VariableDeclarationImpl(
'e',
type: const VoidType(),
@@ -542,10 +556,10 @@ for (null in null) {}''',
new InternalForInStatement(
new MultiVariableDeclarationForInElement(
variableDeclarations: [
new VariableDeclaration(
new InternalVariableDeclaration(
new VariableDeclarationImpl('a', fileOffset: -1),
),
new VariableDeclaration(
new InternalVariableDeclaration(
new VariableDeclarationImpl('b', fileOffset: -1),
),
],
@@ -565,14 +579,14 @@ for (var a, b in null) {}''',
new InternalForInStatement(
new MultiVariableDeclarationForInElement(
variableDeclarations: [
new VariableDeclaration(
new InternalVariableDeclaration(
new VariableDeclarationImpl(
'a',
type: const VoidType(),
fileOffset: -1,
),
),
new VariableDeclaration(
new InternalVariableDeclaration(
new VariableDeclarationImpl('b', fileOffset: -1),
),
],
-2
View File
@@ -1482,8 +1482,6 @@ class VariableStatement extends Statement {
..parent = this;
}
/// Returns a possibly synthesized name for this variable, consistent with
/// the names used across all [toString] calls.
@override
String toString() {
return "VariableStatement(${toStringInternal()})";
-7
View File
@@ -71,7 +71,6 @@ abstract interface class IVariable implements TreeNode, Annotatable {
bool get hasIsWildcard;
bool get hasIsSuperInitializingFormal;
bool get hasIsErroneouslyInitialized;
Variable get asVariableDeclaration;
}
/// The root of the sealed hierarchy of non-type variables.
@@ -186,9 +185,6 @@ sealed class Variable extends VariableBase
@override
bool get isAssignable;
@override
Variable get asVariableDeclaration => this;
abstract String? name;
@override
@@ -646,9 +642,6 @@ class LegacyVariable extends TreeNode implements Variable, Annotatable {
throw new UnsupportedError("${this.runtimeType}.context=");
}
@override
Variable get asVariableDeclaration => this;
@override
Variable get variable => this;