[cfe] Turn wildcard locals into ExpressionStatements or EmptyStatements.
This CL converts VariableDeclarations to ExpressionStatements or EmptyStatements.
If the declaration has an initializer, it will be converted to an ExpressionStatement, otherwise, an EmptyStatement.
This will help the VM and potentially other backends, avoid allocating space for a variable declaration that will never be used.
Bug: https://github.com/dart-lang/sdk/issues/55655
Change-Id: I845b7e5e61fbb0340623ec0dee7269491bc09513
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/373640
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/kernel/body_builder.dart b/pkg/front_end/lib/src/kernel/body_builder.dart
index 050609d..265fbd3 100644
--- a/pkg/front_end/lib/src/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/kernel/body_builder.dart
@@ -4065,13 +4065,26 @@
return;
}
VariableDeclaration variable = node as VariableDeclaration;
- if (annotations != null) {
- for (int i = 0; i < annotations.length; i++) {
- variable.addAnnotation(annotations[i]);
+ if (variable.isWildcard && scope.kind != ScopeKind.forStatement) {
+ // Wildcard variable declarations can be removed, except for the ones in
+ // for loops. This logic turns them into `ExpressionStatement`s or
+ // `EmptyStatement`s so the backends don't need to allocate space for
+ // them.
+ if (variable.initializer case var initializer?) {
+ push(forest.createExpressionStatement(
+ offsetForToken(endToken), initializer));
+ } else {
+ push(forest.createEmptyStatement(offsetForToken(endToken)));
}
- (variablesWithMetadata ??= <VariableDeclaration>[]).add(variable);
+ } else {
+ if (annotations != null) {
+ for (int i = 0; i < annotations.length; i++) {
+ variable.addAnnotation(annotations[i]);
+ }
+ (variablesWithMetadata ??= <VariableDeclaration>[]).add(variable);
+ }
+ push(variable);
}
- push(variable);
} else {
List<VariableDeclaration>? variables =
const FixedNullableList<VariableDeclaration>()
@@ -4085,19 +4098,52 @@
push(new ParserRecovery(offsetForToken(endToken)));
return;
}
- if (annotations != null) {
- VariableDeclaration first = variables.first;
- for (int i = 0; i < annotations.length; i++) {
- first.addAnnotation(annotations[i]);
+ if (scope.kind != ScopeKind.forStatement) {
+ // Wildcard variable declarations can be removed, except for the ones in
+ // for loops. This logic turns them into `ExpressionStatement`s or
+ // `EmptyStatement`s so the backends don't need to allocate space for
+ // them.
+ List<Statement> declarationStatements = [];
+ for (VariableDeclaration variable in variables) {
+ if (variable.isWildcard) {
+ if (variable.initializer case var initializer?) {
+ declarationStatements.add(forest.createExpressionStatement(
+ offsetForToken(endToken), initializer));
+ } else {
+ declarationStatements
+ .add(forest.createEmptyStatement(offsetForToken(endToken)));
+ }
+ } else {
+ declarationStatements.add(variable);
+ }
}
- (multiVariablesWithMetadata ??= <List<VariableDeclaration>>[])
- .add(variables);
+ Object variablesDeclaration =
+ forest.variablesDeclaration(declarationStatements, uri);
+ addVariableAnnotations(
+ forest
+ .variablesDeclarationExtractDeclarations(variablesDeclaration),
+ annotations);
+ push(variablesDeclaration);
+ } else {
+ addVariableAnnotations(variables, annotations);
+ push(forest.variablesDeclaration(variables, uri));
}
- push(forest.variablesDeclaration(variables, uri));
}
_exitLocalState();
}
+ void addVariableAnnotations(List<VariableDeclaration> annotationVariables,
+ List<Expression>? annotations) {
+ if (annotations != null && annotationVariables.isNotEmpty) {
+ VariableDeclaration first = annotationVariables.first;
+ for (int i = 0; i < annotations.length; i++) {
+ first.addAnnotation(annotations[i]);
+ }
+ (multiVariablesWithMetadata ??= <List<VariableDeclaration>>[])
+ .add(annotationVariables);
+ }
+ }
+
/// Stack containing assigned variables info for try statements.
///
/// These are created in [beginTryStatement] and ended in either [beginBlock]
diff --git a/pkg/front_end/lib/src/kernel/forest.dart b/pkg/front_end/lib/src/kernel/forest.dart
index 6853223..0d4e439 100644
--- a/pkg/front_end/lib/src/kernel/forest.dart
+++ b/pkg/front_end/lib/src/kernel/forest.dart
@@ -371,7 +371,7 @@
Statement statement = statements[i];
if (statement is _VariablesDeclaration) {
copy ??= new List<Statement>.of(statements.getRange(0, i));
- copy.addAll(statement.declarations);
+ copy.addAll(statement.variableOrWildcardInitializers);
} else if (copy != null) {
copy.add(statement);
}
@@ -547,19 +547,20 @@
}
_VariablesDeclaration variablesDeclaration(
- List<VariableDeclaration> declarations, Uri uri) {
- return new _VariablesDeclaration(declarations, uri);
+ List<Statement> statements, Uri uri) {
+ return new _VariablesDeclaration(statements, uri);
}
List<VariableDeclaration> variablesDeclarationExtractDeclarations(
Object? variablesDeclaration) {
- return (variablesDeclaration as _VariablesDeclaration).declarations;
+ return (variablesDeclaration as _VariablesDeclaration).variables;
}
Statement wrapVariables(Statement statement) {
if (statement is _VariablesDeclaration) {
- return new Block(
- new List<Statement>.of(statement.declarations, growable: true))
+ return new Block(new List<Statement>.of(
+ statement.variableOrWildcardInitializers,
+ growable: true))
..fileOffset = statement.fileOffset;
} else if (statement is VariableDeclaration) {
return new Block(<Statement>[statement])
@@ -908,11 +909,19 @@
}
class _VariablesDeclaration extends AuxiliaryStatement {
- final List<VariableDeclaration> declarations;
+ /// A list of variable declarations with [ExpressionStatement]s and
+ /// [EmptyStatement]s from wildcard variable declarations.
+ final List<Statement> variableOrWildcardInitializers;
+
+ // A list of variable declarations that are not wildcard variables.
+ final List<VariableDeclaration> variables = [];
final Uri uri;
- _VariablesDeclaration(this.declarations, this.uri) {
- setParents(declarations, this);
+ _VariablesDeclaration(this.variableOrWildcardInitializers, this.uri) {
+ setParents(variableOrWildcardInitializers, this);
+ for (Statement statement in variableOrWildcardInitializers) {
+ if (statement is VariableDeclaration) variables.add(statement);
+ }
}
@override
@@ -953,12 +962,19 @@
@override
// Coverage-ignore(suite): Not run.
void toTextInternal(AstPrinter printer) {
- for (int index = 0; index < declarations.length; index++) {
+ for (int index = 0;
+ index < variableOrWildcardInitializers.length;
+ index++) {
+ Statement statement = variableOrWildcardInitializers[index];
if (index > 0) {
printer.write(', ');
}
- printer.writeVariableDeclaration(declarations[index],
- includeModifiersAndType: index == 0);
+ if (statement is VariableDeclaration) {
+ printer.writeVariableDeclaration(statement,
+ includeModifiersAndType: index == 0);
+ } else {
+ printer.writeStatement(statement);
+ }
}
printer.write(';');
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.expect b/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.expect
index 28e17e5..4551186 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.expect
@@ -8,8 +8,8 @@
: super core::Object::•()
;
method member() → void {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
this.{self::Field::_} = 3;
}
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.modular.expect b/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.modular.expect
index 28e17e5..4551186 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.modular.expect
@@ -8,8 +8,8 @@
: super core::Object::•()
;
method member() → void {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
this.{self::Field::_} = 3;
}
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.transformed.expect b/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.transformed.expect
index 28e17e5..4551186 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_member_no_shadowing.dart.strong.transformed.expect
@@ -8,8 +8,8 @@
: super core::Object::•()
;
method member() → void {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
this.{self::Field::_} = 3;
}
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var.dart b/pkg/front_end/testcases/wildcard_variables/local_var.dart
index deb8542..bfb0647 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var.dart
+++ b/pkg/front_end/testcases/wildcard_variables/local_var.dart
@@ -6,4 +6,13 @@
var _ = 1;
int _ = 2;
_ = 3;
+
+ var _ = 2, _ = 2;
+
+ int test2() => 1;
+ var _ = test2();
+
+ late bool _;
+ late int _, _ = 3, x = 2;
+ late int _ = 3, _ = 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.expect b/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.expect
index 7055440..61b4640 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.expect
@@ -10,9 +10,20 @@
import "dart:core" as core;
static method test() → dynamic {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
invalid-expression "pkg/front_end/testcases/wildcard_variables/local_var.dart:8:3: Error: Setter not found: '_'.
_ = 3;
^";
+ 2;
+ 2;
+ function test2() → core::int
+ return 1;
+ test2(){() → core::int};
+ ;
+ ;
+ 3;
+ late core::int x = 2;
+ 3;
+ 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.modular.expect b/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.modular.expect
index 7055440..61b4640 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.modular.expect
@@ -10,9 +10,20 @@
import "dart:core" as core;
static method test() → dynamic {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
invalid-expression "pkg/front_end/testcases/wildcard_variables/local_var.dart:8:3: Error: Setter not found: '_'.
_ = 3;
^";
+ 2;
+ 2;
+ function test2() → core::int
+ return 1;
+ test2(){() → core::int};
+ ;
+ ;
+ 3;
+ late core::int x = 2;
+ 3;
+ 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.transformed.expect b/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.transformed.expect
index 7055440..61b4640 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_var.dart.strong.transformed.expect
@@ -10,9 +10,20 @@
import "dart:core" as core;
static method test() → dynamic {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
invalid-expression "pkg/front_end/testcases/wildcard_variables/local_var.dart:8:3: Error: Setter not found: '_'.
_ = 3;
^";
+ 2;
+ 2;
+ function test2() → core::int
+ return 1;
+ test2(){() → core::int};
+ ;
+ ;
+ 3;
+ late core::int x = 2;
+ 3;
+ 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.expect b/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.expect
index 407215a..a8a13e7 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.expect
@@ -4,7 +4,7 @@
static field core::int _ = 100;
static method main() → dynamic {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
self::_ = 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.modular.expect b/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.modular.expect
index 407215a..a8a13e7 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.modular.expect
@@ -4,7 +4,7 @@
static field core::int _ = 100;
static method main() → dynamic {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
self::_ = 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.transformed.expect b/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.transformed.expect
index 407215a..a8a13e7 100644
--- a/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_no_shadowing.dart.strong.transformed.expect
@@ -4,7 +4,7 @@
static field core::int _ = 100;
static method main() → dynamic {
- wildcard core::int _ = 1;
- wildcard core::int _ = 2;
+ 1;
+ 2;
self::_ = 3;
}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart
new file mode 100644
index 0000000..baefb1b
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+String foo(String s) {
+ print(s);
+ return s;
+}
+
+test() {
+ String a = foo("a"), _ = foo("b"), c = foo("c"), _ = foo("d");
+}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.expect b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.expect
new file mode 100644
index 0000000..ef645cf
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::String s) → core::String {
+ core::print(s);
+ return s;
+}
+static method test() → dynamic {
+ core::String a = self::foo("a");
+ self::foo("b");
+ core::String c = self::foo("c");
+ self::foo("d");
+}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.modular.expect b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.modular.expect
new file mode 100644
index 0000000..ef645cf
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.modular.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::String s) → core::String {
+ core::print(s);
+ return s;
+}
+static method test() → dynamic {
+ core::String a = self::foo("a");
+ self::foo("b");
+ core::String c = self::foo("c");
+ self::foo("d");
+}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.outline.expect b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.outline.expect
new file mode 100644
index 0000000..337677d
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::String s) → core::String
+ ;
+static method test() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.transformed.expect b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.transformed.expect
new file mode 100644
index 0000000..ef645cf
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.strong.transformed.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::String s) → core::String {
+ core::print(s);
+ return s;
+}
+static method test() → dynamic {
+ core::String a = self::foo("a");
+ self::foo("b");
+ core::String c = self::foo("c");
+ self::foo("d");
+}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.textual_outline.expect b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.textual_outline.expect
new file mode 100644
index 0000000..a53117e
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+String foo(String s) {}
+
+test() {}
diff --git a/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..a53117e
--- /dev/null
+++ b/pkg/front_end/testcases/wildcard_variables/local_var_order.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+String foo(String s) {}
+
+test() {}