diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart index ca793b3ff62..834df9c6f3f 100644 --- a/pkg/front_end/lib/src/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/kernel/body_builder.dart @@ -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? variables = - const FixedNullableList().popNonNullable( + List? variables = + const FixedNullableList().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? _buildForLoopVariableDeclarations( + List? _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) { // Coverage-ignore-block(suite): Not run. - List variables = []; + List 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? variables; - List? intermediateVariables; + List? variables; + List? intermediateVariables; if (variableOrExpression is InternalPatternVariableDeclaration) { variables = (pop() as List) .map(intern.createVariableDeclaration) @@ -4090,8 +4092,8 @@ class BodyBuilderImpl extends StackListenerImpl .deferNode(); Object? variableOrExpression = pop(); - List? variables; - List? intermediateVariables; + List? variables; + List? intermediateVariables; if (variableOrExpression is InternalPatternVariableDeclaration) { variables = (pop() as List) .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. diff --git a/pkg/front_end/lib/src/kernel/collections.dart b/pkg/front_end/lib/src/kernel/collections.dart index 593de68cecb..d15326a843b 100644 --- a/pkg/front_end/lib/src/kernel/collections.dart +++ b/pkg/front_end/lib/src/kernel/collections.dart @@ -222,7 +222,7 @@ class ForElement extends ControlFlowElement implements ForElementBase { // May be empty, but not null. @override - final List variables; + final List 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 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 get variables; + List get internalVariables; abstract Expression? condition; List get updates; abstract Expression body; + + /// [VariableDeclaration]s computed after inference of [internalVariables]. + abstract List variables; } class PatternForElement extends ControlFlowElementImpl with ControlFlowElementMixin implements ForElementBase { InternalPatternVariableDeclaration internalPatternVariableDeclaration; - List intermediateVariables; + List intermediateVariables; // May be empty, but not null. @override - final List variables; + final List internalVariables; @override Expression? condition; // May be null. @@ -489,10 +493,13 @@ class PatternForElement extends ControlFlowElementImpl /// [internalPatternVariableDeclaration]. late PatternVariableDeclaration patternVariableDeclaration; + @override + late List 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 get variables; + List get internalVariables; abstract Expression? condition; List get updates; abstract MapLiteralEntry body; + + /// [VariableDeclaration]s computed after inference of [internalVariables]. + abstract List 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 variables; + final List 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 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 intermediateVariables; + List intermediateVariables; @override - final List variables; + final List internalVariables; @override Expression? condition; @@ -767,10 +780,13 @@ class PatternForMapEntry extends TreeNode /// [internalPatternVariableDeclaration]. late PatternVariableDeclaration patternVariableDeclaration; + @override + late List 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); diff --git a/pkg/front_end/lib/src/kernel/external_ast_helper.dart b/pkg/front_end/lib/src/kernel/external_ast_helper.dart index d3347f77666..9679e489334 100644 --- a/pkg/front_end/lib/src/kernel/external_ast_helper.dart +++ b/pkg/front_end/lib/src/kernel/external_ast_helper.dart @@ -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? 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 variables, + required Expression? condition, + required List updates, + required Statement body, + required Scope? scope, + required int fileOffset, +}) { + return new ForStatement(variables, condition, updates, body) + ..scope = scope + ..fileOffset = fileOffset; +} diff --git a/pkg/front_end/lib/src/kernel/internal_ast.dart b/pkg/front_end/lib/src/kernel/internal_ast.dart index bf7c05e12f9..afc0fe4af4a 100644 --- a/pkg/front_end/lib/src/kernel/internal_ast.dart +++ b/pkg/front_end/lib/src/kernel/internal_ast.dart @@ -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? 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 variableDeclarations; + final List 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(TreeVisitor v) { + unsupported("${runtimeType}.accept on ${v.runtimeType}", -1, null); + } + + @override + // Coverage-ignore(suite): Not run. + R accept1(TreeVisitor1 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 variables; + final Expression? condition; // May be null. + final List 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); diff --git a/pkg/front_end/lib/src/kernel/internal_ast_helper.dart b/pkg/front_end/lib/src/kernel/internal_ast_helper.dart index 8719bdec018..47a17e15bd4 100644 --- a/pkg/front_end/lib/src/kernel/internal_ast_helper.dart +++ b/pkg/front_end/lib/src/kernel/internal_ast_helper.dart @@ -129,7 +129,7 @@ Block createBlock( Statement statement = statements[i]; if (statement is _VariablesDeclaration) { copy ??= new List.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 variables, + List variables, Expression? condition, List updates, Expression body, @@ -410,7 +410,7 @@ ForInStatement createForInStatement( ForMapEntry createForMapEntry( int fileOffset, - List variables, + List variables, Expression? condition, List updates, MapLiteralEntry body, @@ -422,12 +422,12 @@ ForMapEntry createForMapEntry( /// Return a representation of a for statement. Statement createForStatement( int fileOffset, - List? variables, + List? variables, Expression? condition, List 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 intermediateVariables, - required List variables, + required List intermediateVariables, + required List variables, required Expression? condition, required List 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 intermediateVariables, - required List variableInitializations, + required List intermediateVariables, + required List variableInitializations, required Expression? condition, required List 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 declarations, + List declarations, Uri uri, ) { return new _VariablesDeclaration(declarations, uri); } -List variablesDeclarationExtractDeclarations( +List 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])..fileOffset = statement.fileOffset; } else { return statement; @@ -1743,7 +1743,7 @@ Statement wrapVariables(Statement statement) { } class _VariablesDeclaration extends AuxiliaryStatement { - final List declarations; + final List 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, ); } diff --git a/pkg/front_end/lib/src/type_inference/inference_results.dart b/pkg/front_end/lib/src/type_inference/inference_results.dart index 5702a589110..4aa388a0412 100644 --- a/pkg/front_end/lib/src/type_inference/inference_results.dart +++ b/pkg/front_end/lib/src/type_inference/inference_results.dart @@ -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. diff --git a/pkg/front_end/lib/src/type_inference/inference_visitor.dart b/pkg/front_end/lib/src/type_inference/inference_visitor.dart index 9e2c43f1094..cfc39669659 100644 --- a/pkg/front_end/lib/src/type_inference/inference_visitor.dart +++ b/pkg/front_end/lib/src/type_inference/inference_visitor.dart @@ -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 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 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 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 inferredSpreadTypes, Map inferredConditionTypes, ) { - for (int index = 0; index < element.variables.length; index++) { - VariableDeclaration variableDeclaration = element.variables[index]; - Variable variable = variableDeclaration.variable; - if (variable.name == null) { + List 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 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 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 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 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 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 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 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 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 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 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? 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 variableDeclarations = []; List 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 diff --git a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart index 4d0173bcf48..5cf3874f9b3 100644 --- a/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart +++ b/pkg/front_end/test/text_representation/internal_ast_text_representation_test.dart @@ -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), ), ], diff --git a/pkg/kernel/lib/src/ast/statements.dart b/pkg/kernel/lib/src/ast/statements.dart index b53f3ef8009..51fc62cd903 100644 --- a/pkg/kernel/lib/src/ast/statements.dart +++ b/pkg/kernel/lib/src/ast/statements.dart @@ -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()})"; diff --git a/pkg/kernel/lib/src/ast/variables.dart b/pkg/kernel/lib/src/ast/variables.dart index 05ca3ca0040..f6c569ad326 100644 --- a/pkg/kernel/lib/src/ast/variables.dart +++ b/pkg/kernel/lib/src/ast/variables.dart @@ -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;