Don't use variableElement.computeConstantValue() in ConstantVisitor.

...when we are using Analysis Driver.

This method causes switching to the task-model based way of computing
constants. And so filling  SdkAnalysisContext with data. And because
SDK instances are long-lived, we were keeping this data as well.

R=brianwilkerson@google.com

Change-Id: Ie6f4a4ce8a05238b9640aef961af394d64373573
Reviewed-on: https://dart-review.googlesource.com/c/78420
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index f28c8c5..bdd8592 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -60,7 +60,7 @@
   final List<UsedImportedElements> _usedImportedElementsList = [];
   final List<UsedLocalElements> _usedLocalElementsList = [];
   final Map<FileState, List<PendingError>> _fileToPendingErrors = {};
-  final List<ConstantEvaluationTarget> _constants = [];
+  final Set<ConstantEvaluationTarget> _constants = new Set();
 
   LibraryAnalyzer(
       this._analysisOptions,
@@ -162,7 +162,8 @@
   void _computeConstantErrors(
       ErrorReporter errorReporter, CompilationUnit unit) {
     ConstantVerifier constantVerifier = new ConstantVerifier(
-        errorReporter, _libraryElement, _typeProvider, _declaredVariables);
+        errorReporter, _libraryElement, _typeProvider, _declaredVariables,
+        forAnalysisDriver: true);
     unit.accept(constantVerifier);
   }
 
@@ -172,7 +173,7 @@
   void _computeConstants() {
     ConstantEvaluationEngine evaluationEngine = new ConstantEvaluationEngine(
         _typeProvider, _declaredVariables,
-        typeSystem: _context.typeSystem);
+        forAnalysisDriver: true, typeSystem: _context.typeSystem);
 
     List<_ConstantNode> nodes = [];
     Map<ConstantEvaluationTarget, _ConstantNode> nodeMap = {};
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index 2b66eb0..d333f97 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -51,17 +51,23 @@
   /// The current library that is being analyzed.
   final LibraryElement _currentLibrary;
 
+  ConstantEvaluationEngine _evaluationEngine;
+
   /// Initialize a newly created constant verifier.
   ///
   /// @param errorReporter the error reporter by which errors will be reported
   ConstantVerifier(this._errorReporter, LibraryElement currentLibrary,
-      this._typeProvider, this.declaredVariables)
+      this._typeProvider, this.declaredVariables,
+      {bool forAnalysisDriver: false})
       : _currentLibrary = currentLibrary,
         _typeSystem = currentLibrary.context.typeSystem {
     this._boolType = _typeProvider.boolType;
     this._intType = _typeProvider.intType;
     this._numType = _typeProvider.numType;
     this._stringType = _typeProvider.stringType;
+    this._evaluationEngine = new ConstantEvaluationEngine(
+        _typeProvider, declaredVariables,
+        forAnalysisDriver: forAnalysisDriver, typeSystem: _typeSystem);
   }
 
   @override
@@ -123,12 +129,9 @@
       // evaluation.
       ConstructorElement constructor = node.staticElement;
       if (constructor != null) {
-        ConstantEvaluationEngine evaluationEngine =
-            new ConstantEvaluationEngine(_typeProvider, declaredVariables,
-                typeSystem: _typeSystem);
         ConstantVisitor constantVisitor =
-            new ConstantVisitor(evaluationEngine, _errorReporter);
-        evaluationEngine.evaluateConstructorCall(
+            new ConstantVisitor(_evaluationEngine, _errorReporter);
+        _evaluationEngine.evaluateConstructorCall(
             node,
             node.argumentList.arguments,
             constructor,
@@ -204,10 +207,8 @@
             AnalysisErrorListener.NULL_LISTENER;
         ErrorReporter subErrorReporter =
             new ErrorReporter(errorListener, _errorReporter.source);
-        DartObjectImpl result = key.accept(new ConstantVisitor(
-            new ConstantEvaluationEngine(_typeProvider, declaredVariables,
-                typeSystem: _typeSystem),
-            subErrorReporter));
+        DartObjectImpl result = key
+            .accept(new ConstantVisitor(_evaluationEngine, subErrorReporter));
         if (result != null) {
           if (keys.contains(result)) {
             invalidKeys.add(key);
@@ -444,10 +445,8 @@
     RecordingErrorListener errorListener = new RecordingErrorListener();
     ErrorReporter subErrorReporter =
         new ErrorReporter(errorListener, _errorReporter.source);
-    DartObjectImpl result = expression.accept(new ConstantVisitor(
-        new ConstantEvaluationEngine(_typeProvider, declaredVariables,
-            typeSystem: _typeSystem),
-        subErrorReporter));
+    DartObjectImpl result = expression
+        .accept(new ConstantVisitor(_evaluationEngine, subErrorReporter));
     _reportErrors(errorListener.errors, errorCode);
     return result;
   }
@@ -545,10 +544,8 @@
                 AnalysisErrorListener.NULL_LISTENER;
             ErrorReporter subErrorReporter =
                 new ErrorReporter(errorListener, _errorReporter.source);
-            DartObjectImpl result = initializer.accept(new ConstantVisitor(
-                new ConstantEvaluationEngine(_typeProvider, declaredVariables,
-                    typeSystem: _typeSystem),
-                subErrorReporter));
+            DartObjectImpl result = initializer.accept(
+                new ConstantVisitor(_evaluationEngine, subErrorReporter));
             if (result == null) {
               _errorReporter.reportErrorForNode(
                   CompileTimeErrorCode
@@ -574,9 +571,8 @@
     ErrorReporter subErrorReporter =
         new ErrorReporter(errorListener, _errorReporter.source);
     DartObjectImpl result = expression.accept(
-        new _ConstantVerifier_validateInitializerExpression(_typeProvider,
-            subErrorReporter, this, parameterElements, declaredVariables,
-            typeSystem: _typeSystem));
+        new _ConstantVerifier_validateInitializerExpression(_typeSystem,
+            _evaluationEngine, subErrorReporter, this, parameterElements));
     _reportErrors(errorListener.errors,
         CompileTimeErrorCode.NON_CONSTANT_VALUE_IN_INITIALIZER);
     if (result != null) {
@@ -606,24 +602,18 @@
 }
 
 class _ConstantVerifier_validateInitializerExpression extends ConstantVisitor {
+  final TypeSystem typeSystem;
   final ConstantVerifier verifier;
 
   List<ParameterElement> parameterElements;
 
-  TypeSystem _typeSystem;
-
   _ConstantVerifier_validateInitializerExpression(
-      TypeProvider typeProvider,
+      this.typeSystem,
+      ConstantEvaluationEngine evaluationEngine,
       ErrorReporter errorReporter,
       this.verifier,
-      this.parameterElements,
-      DeclaredVariables declaredVariables,
-      {TypeSystem typeSystem})
-      : _typeSystem = typeSystem ?? new StrongTypeSystemImpl(typeProvider),
-        super(
-            new ConstantEvaluationEngine(typeProvider, declaredVariables,
-                typeSystem: typeSystem),
-            errorReporter);
+      this.parameterElements)
+      : super(evaluationEngine, errorReporter);
 
   @override
   DartObjectImpl visitSimpleIdentifier(SimpleIdentifier node) {
@@ -637,20 +627,20 @@
           if (type.isDynamic) {
             return new DartObjectImpl(
                 verifier._typeProvider.objectType, DynamicState.DYNAMIC_STATE);
-          } else if (_typeSystem.isSubtypeOf(type, verifier._boolType)) {
+          } else if (typeSystem.isSubtypeOf(type, verifier._boolType)) {
             return new DartObjectImpl(
                 verifier._typeProvider.boolType, BoolState.UNKNOWN_VALUE);
-          } else if (_typeSystem.isSubtypeOf(
+          } else if (typeSystem.isSubtypeOf(
               type, verifier._typeProvider.doubleType)) {
             return new DartObjectImpl(
                 verifier._typeProvider.doubleType, DoubleState.UNKNOWN_VALUE);
-          } else if (_typeSystem.isSubtypeOf(type, verifier._intType)) {
+          } else if (typeSystem.isSubtypeOf(type, verifier._intType)) {
             return new DartObjectImpl(
                 verifier._typeProvider.intType, IntState.UNKNOWN_VALUE);
-          } else if (_typeSystem.isSubtypeOf(type, verifier._numType)) {
+          } else if (typeSystem.isSubtypeOf(type, verifier._numType)) {
             return new DartObjectImpl(
                 verifier._typeProvider.numType, NumState.UNKNOWN_VALUE);
-          } else if (_typeSystem.isSubtypeOf(type, verifier._stringType)) {
+          } else if (typeSystem.isSubtypeOf(type, verifier._stringType)) {
             return new DartObjectImpl(
                 verifier._typeProvider.stringType, StringState.UNKNOWN_VALUE);
           }
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 80330a4..c016009 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -90,6 +90,11 @@
   final ConstantEvaluationValidator validator;
 
   /**
+   * Whether this engine is used inside Analysis Driver.
+   */
+  final bool forAnalysisDriver;
+
+  /**
    * Initialize a newly created [ConstantEvaluationEngine].  The [typeProvider]
    * is used to access known types.  [_declaredVariables] is the set of
    * variables declared on the command line using '-D'.  The [validator], if
@@ -97,7 +102,9 @@
    * tests.
    */
   ConstantEvaluationEngine(TypeProvider typeProvider, this._declaredVariables,
-      {ConstantEvaluationValidator validator, TypeSystem typeSystem})
+      {ConstantEvaluationValidator validator,
+      TypeSystem typeSystem,
+      this.forAnalysisDriver: false})
       : typeProvider = typeProvider,
         validator =
             validator ?? new ConstantEvaluationValidator_ForProduction(),
@@ -1070,7 +1077,7 @@
   /**
    * Convenience getter to gain access to the [evaluationEngine]'s type system.
    */
-  TypeSystem get _typeSystem => evaluationEngine.typeSystem;
+  TypeSystem get typeSystem => evaluationEngine.typeSystem;
 
   /**
    * Given a [type] that may contain free type variables, evaluate them against
@@ -1211,8 +1218,8 @@
     }
     ParameterizedType thenType = thenResult.type;
     ParameterizedType elseType = elseResult.type;
-    return new DartObjectImpl.validWithUnknownValue(_typeSystem
-        .getLeastUpperBound(thenType, elseType) as ParameterizedType);
+    return new DartObjectImpl.validWithUnknownValue(
+        typeSystem.getLeastUpperBound(thenType, elseType) as ParameterizedType);
   }
 
   @override
@@ -1502,11 +1509,23 @@
     Element variableElement =
         element is PropertyAccessorElement ? element.variable : element;
     if (variableElement is VariableElementImpl) {
-      evaluationEngine.validator.beforeGetEvaluationResult(variableElement);
-      variableElement.computeConstantValue();
-      EvaluationResultImpl value = variableElement.evaluationResult;
-      if (variableElement.isConst && value != null) {
-        return value.value;
+      // We access values of constant variables here in two cases: when we
+      // compute values of other constant  variables, or when we compute values
+      // and errors for other constant expressions. In any case, with Analysis
+      // Driver, we compute values of all dependencies first (or detect  cycle).
+      // So, the value has already been computed. Just return it.
+      if (evaluationEngine.forAnalysisDriver) {
+        if (variableElement.isConst) {
+          return variableElement.evaluationResult.value;
+        }
+      } else {
+        // TODO(scheglov) Once we remove task model, we can remove this code.
+        evaluationEngine.validator.beforeGetEvaluationResult(variableElement);
+        variableElement.computeConstantValue();
+        EvaluationResultImpl value = variableElement.evaluationResult;
+        if (variableElement.isConst && value != null) {
+          return value.value;
+        }
       }
     } else if (variableElement is ExecutableElement) {
       ExecutableElement function = element;
diff --git a/pkg/analyzer/lib/src/dart/constant/utilities.dart b/pkg/analyzer/lib/src/dart/constant/utilities.dart
index 81f3e41..50480ad 100644
--- a/pkg/analyzer/lib/src/dart/constant/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/constant/utilities.dart
@@ -164,6 +164,10 @@
     if (node.isConst) {
       _find(node);
     } else {
+      // Values of keys are computed to check that they are unique.
+      for (var entry in node.entries) {
+        _find(entry.key);
+      }
       super.visitMapLiteral(node);
     }
   }
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 679ca15..e4e4784 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -5555,6 +5555,24 @@
     verify([source]);
   }
 
+  test_recursiveCompileTimeConstant_fromMapLiteral() async {
+    resourceProvider.newFile(
+      resourceProvider.convertPath('/constants.dart'),
+      r'''
+const int x = y;
+const int y = x;
+''',
+    );
+    Source source = addSource(r'''
+import 'constants.dart';
+final z = {x: 0, y: 1};
+''');
+    await computeAnalysisResult(source);
+    // No errors, because the cycle is not in this source.
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   test_recursiveCompileTimeConstant_initializer_after_toplevel_var() async {
     Source source = addSource('''
 const y = const C();
@@ -5587,6 +5605,28 @@
     verify([source]);
   }
 
+  test_recursiveCompileTimeConstant_singleVariable_fromConstList() async {
+    Source source = addSource(r'''
+const elems = const [
+  const [
+    1, elems, 3,
+  ],
+];
+''');
+    await computeAnalysisResult(source);
+    if (!enableNewAnalysisDriver) {
+      assertErrors(source, [
+        CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT,
+      ]);
+    } else {
+      assertErrors(source, [
+        CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT,
+        StrongModeCode.TOP_LEVEL_CYCLE,
+      ]);
+    }
+    verify([source]);
+  }
+
   test_recursiveConstructorRedirect() async {
     Source source = addSource(r'''
 class A {