Clone metadata in BodyBuilder instead of type inference

Change-Id: Iaf1344455c45693902d89c866c93395670e56251
Reviewed-on: https://dart-review.googlesource.com/c/85711
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Peter von der Ahé <ahe@google.com>
Auto-Submit: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index d08726b..7f9c44d 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -216,6 +216,14 @@
   /// invocations are to be resolved in a separate step.
   final List<Expression> redirectingFactoryInvocations = <Expression>[];
 
+  /// Variables with metadata.  Their types need to be inferred late, for
+  /// example, in [finishFunction].
+  List<VariableDeclaration> variablesWithMetadata;
+
+  /// More than one variable declared in a single statement that has metadata.
+  /// Their types need to be inferred late, for example, in [finishFunction].
+  List<List<VariableDeclaration>> multiVariablesWithMetadata;
+
   BodyBuilder(
       this.library,
       this.member,
@@ -547,7 +555,9 @@
       _typeInferrer.inferMetadata(this, annotations);
       Field field = fields.first.target;
       // The first (and often only field) will not get a clone.
-      annotations.forEach((annotation) => field.addAnnotation(annotation));
+      for (int i = 0; i < annotations.length; i++) {
+        field.addAnnotation(annotations[i]);
+      }
       for (int i = 1; i < fields.length; i++) {
         // We have to clone the annotations on the remaining fields.
         field = fields[i].target;
@@ -559,6 +569,7 @@
     }
 
     resolveRedirectingFactoryTargets();
+    finishVariableMetadata();
   }
 
   @override
@@ -833,6 +844,7 @@
     }
 
     resolveRedirectingFactoryTargets();
+    finishVariableMetadata();
   }
 
   void resolveRedirectingFactoryTargets() {
@@ -924,6 +936,36 @@
     redirectingFactoryInvocations.clear();
   }
 
+  void finishVariableMetadata() {
+    List<VariableDeclaration> variablesWithMetadata =
+        this.variablesWithMetadata;
+    this.variablesWithMetadata = null;
+    List<List<VariableDeclaration>> multiVariablesWithMetadata =
+        this.multiVariablesWithMetadata;
+    this.multiVariablesWithMetadata = null;
+
+    if (variablesWithMetadata != null) {
+      for (int i = 0; i < variablesWithMetadata.length; i++) {
+        _typeInferrer?.inferMetadata(
+            this, variablesWithMetadata[i].annotations);
+      }
+    }
+    if (multiVariablesWithMetadata != null) {
+      for (int i = 0; i < multiVariablesWithMetadata.length; i++) {
+        List<VariableDeclaration> variables = multiVariablesWithMetadata[i];
+        List<Expression> annotations = variables.first.annotations;
+        _typeInferrer?.inferMetadata(this, annotations);
+        for (int i = 1; i < variables.length; i++) {
+          cloner ??= new CloneVisitor();
+          VariableDeclaration variable = variables[i];
+          for (int i = 0; i < annotations.length; i++) {
+            variable.addAnnotation(cloner.clone(annotations[i]));
+          }
+        }
+      }
+    }
+  }
+
   @override
   List<Expression> finishMetadata(TreeNode parent) {
     List<Expression> expressions = pop();
@@ -972,6 +1014,7 @@
       temporaryParent = new ListLiteral(expressions);
     }
     resolveRedirectingFactoryTargets();
+    finishVariableMetadata();
     return temporaryParent != null ? temporaryParent.expressions : expressions;
   }
 
@@ -2042,9 +2085,10 @@
       }
       VariableDeclaration variable = node;
       if (annotations != null) {
-        for (Expression annotation in annotations) {
-          variable.addAnnotation(annotation);
+        for (int i = 0; i < annotations.length; i++) {
+          variable.addAnnotation(annotations[i]);
         }
+        (variablesWithMetadata ??= <VariableDeclaration>[]).add(variable);
       }
       push(variable);
     } else {
@@ -2059,17 +2103,12 @@
         return;
       }
       if (annotations != null) {
-        bool isFirstVariable = true;
-        for (VariableDeclarationJudgment variable in variables) {
-          for (Expression annotation in annotations) {
-            variable.addAnnotation(annotation);
-          }
-          if (isFirstVariable) {
-            isFirstVariable = false;
-          } else {
-            variable.infersAnnotations = false;
-          }
+        VariableDeclaration first = variables.first;
+        for (int i = 0; i < annotations.length; i++) {
+          first.addAnnotation(annotations[i]);
         }
+        (multiVariablesWithMetadata ??= <List<VariableDeclaration>>[])
+            .add(variables);
       }
       push(forest.variablesDeclaration(variables, uri));
     }
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 3b44e55..ea35492 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -312,7 +312,6 @@
         ..parent = node;
     }
     if (node._declaresVariable) {
-      inferrer.inferMetadataKeepingHelper(variable.annotations);
       var tempVar =
           new VariableDeclaration(null, type: inferredType, isFinal: true);
       var variableGet = new VariableGet(tempVar)
@@ -1261,30 +1260,6 @@
   }
 
   void visitVariableDeclarationJudgment(VariableDeclarationJudgment node) {
-    if (node.annotationJudgments.isNotEmpty) {
-      if (node.infersAnnotations) {
-        inferrer.inferMetadataKeepingHelper(node.annotationJudgments);
-      }
-
-      // After the inference was done on the annotations, we may clone them for
-      // this instance of VariableDeclaration in order to avoid having the same
-      // annotation node for two VariableDeclaration nodes in a situation like
-      // the following:
-      //
-      //     class Foo { const Foo(List<String> list); }
-      //
-      //     @Foo(const [])
-      //     var x, y;
-      CloneVisitor cloner = new CloneVisitor();
-      for (int i = 0; i < node.annotations.length; ++i) {
-        kernel.Expression annotation = node.annotations[i];
-        if (annotation.parent != node) {
-          node.annotations[i] = cloner.clone(annotation);
-          node.annotations[i].parent = node;
-        }
-      }
-    }
-
     var initializerJudgment = node.initializerJudgment;
     var declaredType = node._implicitlyTyped ? const UnknownType() : node.type;
     DartType inferredType;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index a78410a..13d3a98 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -24,8 +24,6 @@
 
 import 'package:kernel/ast.dart';
 
-import 'package:kernel/clone.dart' show CloneVisitor;
-
 import 'package:kernel/type_algebra.dart' show Substitution;
 
 import '../../base/instrumentation.dart'
@@ -1800,12 +1798,6 @@
   // TODO(ahe): Investigate if this can be removed.
   final bool _isLocalFunction;
 
-  /// The same [annotations] list is used for all [VariableDeclarationJudgment]s
-  /// of a variable declaration statement. But we need to perform inference
-  /// only once. So, we set this flag to `false` for the second and subsequent
-  /// judgments.
-  bool infersAnnotations = true;
-
   VariableDeclarationJudgment(String name, this._functionNestingLevel,
       {this.forSyntheticToken: false,
       Expression initializer,
@@ -1839,8 +1831,6 @@
         _isLocalFunction = false,
         super.forValue(initializer);
 
-  List<Expression> get annotationJudgments => annotations;
-
   Expression get initializerJudgment => initializer;
 
   @override