Issue 43462. Compute constant values in libraries with contain them.

R=brianwilkerson@google.com

Bug: https://github.com/dart-lang/sdk/issues/43462
Change-Id: I82200c06b1a77f634b7c7f30fd3ad7e10eb01ad4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/163280
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/constant/compute.dart b/pkg/analyzer/lib/src/dart/constant/compute.dart
index 81df16c..229cb78 100644
--- a/pkg/analyzer/lib/src/dart/constant/compute.dart
+++ b/pkg/analyzer/lib/src/dart/constant/compute.dart
@@ -82,7 +82,6 @@
       library.typeProvider,
       declaredVariables,
       typeSystem: library.typeSystem,
-      experimentStatus: experimentStatus,
     );
   }
 
diff --git a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
index ffccab6..e6ebdd3 100644
--- a/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
+++ b/pkg/analyzer/lib/src/dart/constant/constant_verifier.dart
@@ -80,7 +80,7 @@
         _intType = _typeProvider.intType,
         _evaluationEngine = ConstantEvaluationEngine(
             _typeProvider, declaredVariables,
-            typeSystem: _typeSystem, experimentStatus: featureSet);
+            typeSystem: _typeSystem);
 
   bool get _isNonNullableByDefault => _currentLibrary.isNonNullableByDefault;
 
@@ -139,7 +139,7 @@
       ConstructorElement constructor = node.constructorName.staticElement;
       if (constructor != null) {
         ConstantVisitor constantVisitor =
-            ConstantVisitor(_evaluationEngine, _errorReporter);
+            ConstantVisitor(_evaluationEngine, _currentLibrary, _errorReporter);
         _evaluationEngine.evaluateConstructorCall(
             node,
             node.argumentList.arguments,
@@ -421,8 +421,8 @@
       _errorReporter.source,
       isNonNullableByDefault: _currentLibrary.isNonNullableByDefault,
     );
-    DartObjectImpl result =
-        expression.accept(ConstantVisitor(_evaluationEngine, subErrorReporter));
+    DartObjectImpl result = expression.accept(
+        ConstantVisitor(_evaluationEngine, _currentLibrary, subErrorReporter));
     _reportErrors(errorListener.errors, errorCode);
     return result;
   }
@@ -520,8 +520,8 @@
               _errorReporter.source,
               isNonNullableByDefault: _currentLibrary.isNonNullableByDefault,
             );
-            DartObjectImpl result = initializer
-                .accept(ConstantVisitor(_evaluationEngine, subErrorReporter));
+            DartObjectImpl result = initializer.accept(ConstantVisitor(
+                _evaluationEngine, _currentLibrary, subErrorReporter));
             if (result == null) {
               _errorReporter.reportErrorForToken(
                   CompileTimeErrorCode
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index ead4938..cd54de6 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -5,6 +5,7 @@
 import 'dart:collection';
 
 import 'package:analyzer/dart/analysis/declared_variables.dart';
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
 import 'package:analyzer/dart/ast/token.dart';
@@ -17,7 +18,6 @@
 import 'package:analyzer/dart/element/type_system.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/dart/constant/from_environment_evaluator.dart';
 import 'package:analyzer/src/dart/constant/has_type_parameter_reference.dart';
 import 'package:analyzer/src/dart/constant/potentially_constant.dart';
@@ -74,9 +74,6 @@
   /// using '-D', and represented as [DeclaredVariables].
   FromEnvironmentEvaluator _fromEnvironmentEvaluator;
 
-  /// Return the object representing the state of active experiments.
-  final ExperimentStatus experimentStatus;
-
   /// Validator used to verify correct dependency analysis when running unit
   /// tests.
   final ConstantEvaluationValidator validator;
@@ -89,7 +86,6 @@
   ConstantEvaluationEngine(
       TypeProvider typeProvider, DeclaredVariables declaredVariables,
       {ConstantEvaluationValidator validator,
-      ExperimentStatus experimentStatus,
       TypeSystem typeSystem,
       // TODO(brianwilkerson) Remove the unused parameter `forAnalysisDriver`.
       @deprecated bool forAnalysisDriver})
@@ -101,8 +97,7 @@
               isNonNullableByDefault: false,
               strictInference: false,
               typeProvider: typeProvider,
-            ),
-        experimentStatus = experimentStatus ?? ExperimentStatus() {
+            ) {
     _fromEnvironmentEvaluator = FromEnvironmentEvaluator(
       typeSystem,
       declaredVariables,
@@ -203,8 +198,8 @@
             constant.source,
             isNonNullableByDefault: _isNonNullableByDefault,
           );
-          DartObjectImpl dartObject =
-              defaultValue.accept(ConstantVisitor(this, errorReporter));
+          DartObjectImpl dartObject = defaultValue
+              .accept(ConstantVisitor(this, constant.library, errorReporter));
           constant.evaluationResult =
               EvaluationResultImpl(dartObject, errorListener.errors);
         } else {
@@ -220,8 +215,8 @@
           constant.source,
           isNonNullableByDefault: _isNonNullableByDefault,
         );
-        DartObjectImpl dartObject =
-            constantInitializer.accept(ConstantVisitor(this, errorReporter));
+        DartObjectImpl dartObject = constantInitializer
+            .accept(ConstantVisitor(this, constant.library, errorReporter));
         // Only check the type for truly const declarations (don't check final
         // fields with initializers, since their types may be generic.  The type
         // of the final field will be checked later, when the constructor is
@@ -274,7 +269,8 @@
           constant.source,
           isNonNullableByDefault: _isNonNullableByDefault,
         );
-        ConstantVisitor constantVisitor = ConstantVisitor(this, errorReporter);
+        ConstantVisitor constantVisitor =
+            ConstantVisitor(this, constant.library, errorReporter);
         DartObjectImpl result = evaluateConstructorCall(
             constNode,
             constNode.arguments.arguments,
@@ -653,6 +649,7 @@
     }
     ConstantVisitor initializerVisitor = ConstantVisitor(
       this,
+      constructor.library,
       externalErrorReporter,
       lexicalEnvironment: parameterMap,
       substitution: Substitution.fromInterfaceType(definingClass),
@@ -953,6 +950,9 @@
   /// type provider.
   final ConstantEvaluationEngine evaluationEngine;
 
+  /// The library that contains the constant expression being evaluated.
+  final LibraryElement _library;
+
   final Map<String, DartObjectImpl> _lexicalEnvironment;
   final Substitution _substitution;
 
@@ -973,6 +973,7 @@
   /// The [substitution] is specified for instance creations.
   ConstantVisitor(
     this.evaluationEngine,
+    this._library,
     this._errorReporter, {
     Map<String, DartObjectImpl> lexicalEnvironment,
     Substitution substitution,
@@ -981,12 +982,13 @@
     _dartObjectComputer = DartObjectComputer(_errorReporter, evaluationEngine);
   }
 
-  /// Return the object representing the state of active experiments.
-  ExperimentStatus get experimentStatus => evaluationEngine.experimentStatus;
-
   /// Convenience getter to gain access to the [evaluationEngine]'s type system.
   TypeSystemImpl get typeSystem => evaluationEngine.typeSystem;
 
+  bool get _isEnabledConstantUpdate2018 {
+    return _library.featureSet.isEnabled(Feature.constant_update_2018);
+  }
+
   bool get _isNonNullableByDefault => typeSystem.isNonNullableByDefault;
 
   /// Convenience getter to gain access to the [evaluationEngine]'s type
@@ -1009,7 +1011,7 @@
 
   @override
   DartObjectImpl visitAsExpression(AsExpression node) {
-    if (experimentStatus.constant_update_2018) {
+    if (_isEnabledConstantUpdate2018) {
       DartObjectImpl expressionResult = node.expression.accept(this);
       DartObjectImpl typeResult = node.type.accept(this);
       return _dartObjectComputer.castToType(node, expressionResult, typeResult);
@@ -1031,7 +1033,7 @@
       return _dartObjectComputer.lazyOr(
           node, leftResult, () => node.rightOperand.accept(this));
     } else if (operatorType == TokenType.QUESTION_QUESTION) {
-      if (experimentStatus.constant_update_2018) {
+      if (_isEnabledConstantUpdate2018) {
         return _dartObjectComputer.lazyQuestionQuestion(
             node, leftResult, () => node.rightOperand.accept(this));
       } else {
@@ -1043,17 +1045,17 @@
     DartObjectImpl rightResult = node.rightOperand.accept(this);
     if (operatorType == TokenType.AMPERSAND) {
       return _dartObjectComputer.eagerAnd(
-          node, leftResult, rightResult, experimentStatus.constant_update_2018);
+          node, leftResult, rightResult, _isEnabledConstantUpdate2018);
     } else if (operatorType == TokenType.BANG_EQ) {
       return _dartObjectComputer.notEqual(node, leftResult, rightResult);
     } else if (operatorType == TokenType.BAR) {
       return _dartObjectComputer.eagerOr(
-          node, leftResult, rightResult, experimentStatus.constant_update_2018);
+          node, leftResult, rightResult, _isEnabledConstantUpdate2018);
     } else if (operatorType == TokenType.CARET) {
       return _dartObjectComputer.eagerXor(
-          node, leftResult, rightResult, experimentStatus.constant_update_2018);
+          node, leftResult, rightResult, _isEnabledConstantUpdate2018);
     } else if (operatorType == TokenType.EQ_EQ) {
-      if (experimentStatus.constant_update_2018) {
+      if (_isEnabledConstantUpdate2018) {
         return _dartObjectComputer.lazyEqualEqual(
             node, leftResult, rightResult);
       }
@@ -1106,7 +1108,7 @@
   DartObjectImpl visitConditionalExpression(ConditionalExpression node) {
     Expression condition = node.condition;
     DartObjectImpl conditionResult = condition.accept(this);
-    if (experimentStatus.constant_update_2018) {
+    if (_isEnabledConstantUpdate2018) {
       if (conditionResult == null) {
         return conditionResult;
       } else if (!conditionResult.isBool) {
@@ -1228,7 +1230,7 @@
 
   @override
   DartObjectImpl visitIsExpression(IsExpression node) {
-    if (experimentStatus.constant_update_2018) {
+    if (_isEnabledConstantUpdate2018) {
       DartObjectImpl expressionResult = node.expression.accept(this);
       DartObjectImpl typeResult = node.type.accept(this);
       return _dartObjectComputer.typeTest(node, expressionResult, typeResult);
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 90abe81..e79ed4e 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -4,11 +4,12 @@
 
 import 'package:analyzer/dart/analysis/declared_variables.dart';
 import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/element/type_provider.dart';
+import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
+import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart' show TypeSystemImpl;
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/engine.dart' show RecordingErrorListener;
@@ -99,25 +100,17 @@
   /// The source containing the expression(s) that will be evaluated.
   final Source _source;
 
-  /// The type provider used to access the known types.
-  final TypeProvider _typeProvider;
-
-  /// The type system primitives.
-  final TypeSystemImpl _typeSystem;
+  /// The library containing the expression(s) that will be evaluated.
+  final LibraryElement _library;
 
   /// Initialize a newly created evaluator to evaluate expressions in the given
   /// [source]. The [typeProvider] is the type provider used to access known
   /// types.
-  ConstantEvaluator(this._source, TypeProvider typeProvider,
-      {TypeSystemImpl typeSystem})
-      : _typeSystem = typeSystem ??
-            TypeSystemImpl(
-              implicitCasts: true,
-              isNonNullableByDefault: false,
-              strictInference: false,
-              typeProvider: typeProvider,
-            ),
-        _typeProvider = typeProvider;
+  ConstantEvaluator(this._source, LibraryElement library) : _library = library;
+
+  TypeProviderImpl get _typeProvider => _library.typeProvider;
+
+  TypeSystemImpl get _typeSystem => _library.typeSystem;
 
   EvaluationResult evaluate(Expression expression) {
     RecordingErrorListener errorListener = RecordingErrorListener();
@@ -129,6 +122,7 @@
     DartObjectImpl result = expression.accept(ConstantVisitor(
         ConstantEvaluationEngine(_typeProvider, DeclaredVariables(),
             typeSystem: _typeSystem),
+        _library,
         errorReporter));
     List<AnalysisError> errors = errorListener.errors;
     if (errors.isNotEmpty) {
diff --git a/pkg/analyzer/lib/src/lint/linter.dart b/pkg/analyzer/lib/src/lint/linter.dart
index edabdfa..0f81810 100644
--- a/pkg/analyzer/lib/src/lint/linter.dart
+++ b/pkg/analyzer/lib/src/lint/linter.dart
@@ -359,6 +359,7 @@
         declaredVariables,
         typeSystem: typeSystem,
       ),
+      libraryElement,
       errorReporter,
     );
 
diff --git a/pkg/analyzer/test/generated/constant_test.dart b/pkg/analyzer/test/generated/constant_test.dart
index 097479c..996f5cc 100644
--- a/pkg/analyzer/test/generated/constant_test.dart
+++ b/pkg/analyzer/test/generated/constant_test.dart
@@ -501,8 +501,7 @@
     var file = getFile(result.path);
     var evaluator = ConstantEvaluator(
       file.createSource(result.uri),
-      result.typeProvider,
-      typeSystem: result.typeSystem,
+      result.libraryElement,
     );
 
     return evaluator.evaluate(expression);
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 6cd1ae9..1c5816f 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/src/dart/analysis/experiments.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/constant.dart';
-import 'package:analyzer/src/generated/engine.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -306,8 +305,6 @@
     Map<String, String> declaredVariables = const {},
     Map<String, DartObjectImpl> lexicalEnvironment,
   }) {
-    var analysisContext = contextFor(this.result.path);
-    var options = analysisContext.analysisOptions as AnalysisOptionsImpl;
     var expression = findNode.topVariableDeclarationByName(name).initializer;
 
     var source = this.result.unit.declaredElement.source;
@@ -323,9 +320,9 @@
         ConstantEvaluationEngine(
           typeProvider,
           DeclaredVariables.fromMap(declaredVariables),
-          experimentStatus: options.experimentStatus,
           typeSystem: this.result.typeSystem,
         ),
+        this.result.libraryElement,
         errorReporter,
         lexicalEnvironment: lexicalEnvironment,
       ),
diff --git a/pkg/analyzer/test/src/dart/resolution/constant_test.dart b/pkg/analyzer/test/src/dart/resolution/constant_test.dart
index cfe11e5..34b271d 100644
--- a/pkg/analyzer/test/src/dart/resolution/constant_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/constant_test.dart
@@ -232,6 +232,25 @@
     var a = findElement.topVar('a') as ConstVariableElement;
     expect(a.computeConstantValue().toIntValue(), 42);
   }
+
+  /// See https://github.com/dart-lang/sdk/issues/43462
+  test_useLanguageVersionOfEnclosingLibrary() async {
+    newFile('$testPackageLibPath/a.dart', content: r'''
+class Wrapper {
+  final int value;
+  const Wrapper(Object value) : value = value as int;
+}
+''');
+
+    await assertNoErrorsInCode(r'''
+// @dart = 2.4
+import 'a.dart';
+
+void f() {
+  const Wrapper(0);
+}
+''');
+  }
 }
 
 @reflectiveTest