Use the right type provider based on the feature set of the library

Change-Id: I82a22cef142b89579c19e2063fb888e2827f2bb8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104362
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Mike Fairhurst <mfairhurst@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@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 699c335..f3b0f77 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 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/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
@@ -62,7 +63,7 @@
   final AnalysisContext _context;
   final ElementResynthesizer _resynthesizer;
   final LinkedElementFactory _elementFactory;
-  final TypeProvider _typeProvider;
+  TypeProvider _typeProvider;
 
   final TypeSystem _typeSystem;
   LibraryElement _libraryElement;
@@ -97,8 +98,7 @@
       this._inheritance,
       this._library,
       this._resourceProvider)
-      : _typeProvider = _context.typeProvider,
-        _typeSystem = _context.typeSystem;
+      : _typeSystem = _context.typeSystem;
 
   /**
    * Compute analysis results for all units of the library.
@@ -124,7 +124,19 @@
     timerLibraryAnalyzerFreshUnit.stop();
 
     // Resolve URIs in directives to corresponding sources.
+    FeatureSet featureSet = units[_library].featureSet;
+    _typeProvider = _context.typeProvider;
+    if (featureSet.isEnabled(Feature.non_nullable)) {
+      if (_typeProvider is! NonNullableTypeProvider) {
+        _typeProvider = NonNullableTypeProvider.from(_typeProvider);
+      }
+    } else {
+      if (_typeProvider is NonNullableTypeProvider) {
+        _typeProvider = TypeProviderImpl.from(_typeProvider);
+      }
+    }
     units.forEach((file, unit) {
+      _validateFeatureSet(unit, featureSet);
       _resolveUriBasedDirectives(file, unit);
     });
 
@@ -724,6 +736,15 @@
     }
   }
 
+  /// Validate that the feature set associated with the compilation [unit] is
+  /// the same as the [expectedSet] of features supported by the library.
+  void _validateFeatureSet(CompilationUnit unit, FeatureSet expectedSet) {
+    FeatureSet actualSet = unit.featureSet;
+    if (actualSet != expectedSet) {
+      // TODO(brianwilkerson) Generate a diagnostic.
+    }
+  }
+
   /**
    * Check the given [directive] to see if the referenced source exists and
    * report an error if it does not.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 3791919..ca7835f 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -2340,7 +2340,12 @@
         featureSet: _featureSet)) {
       return;
     }
-    _errorReporter.reportErrorForNode(errorCode, expression, arguments);
+    if (expressionType.element == type.element) {
+      _errorReporter.reportErrorForNode(
+          StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, expression);
+    } else {
+      _errorReporter.reportErrorForNode(errorCode, expression, arguments);
+    }
   }
 
   bool _checkForAssignableExpression(
@@ -4570,8 +4575,6 @@
   /**
    * Verify that the given [assertion] has either a 'bool' or '() -> bool'
    * condition.
-   *
-   * See [StaticTypeWarningCode.NON_BOOL_EXPRESSION].
    */
   void _checkForNonBoolExpression(Assertion assertion) {
     Expression expression = assertion.condition;
@@ -4579,8 +4582,13 @@
     if (type is InterfaceType) {
       if (!_typeSystem.isAssignableTo(type, _boolType,
           featureSet: _featureSet)) {
-        _errorReporter.reportErrorForNode(
-            StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression);
+        if (type.element == _boolType.element) {
+          _errorReporter.reportErrorForNode(
+              StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, expression);
+        } else {
+          _errorReporter.reportErrorForNode(
+              StaticTypeWarningCode.NON_BOOL_EXPRESSION, expression);
+        }
       }
     } else if (type is FunctionType) {
       _errorReporter.reportErrorForNode(
@@ -4590,16 +4598,19 @@
 
   /**
    * Checks to ensure that the given [expression] is assignable to bool.
-   *
-   * See [StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION].
    */
   void _checkForNonBoolNegationExpression(Expression expression) {
     DartType conditionType = getStaticType(expression);
     if (conditionType != null &&
         !_typeSystem.isAssignableTo(conditionType, _boolType,
             featureSet: _featureSet)) {
-      _errorReporter.reportErrorForNode(
-          StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION, expression);
+      if (conditionType.element == _boolType.element) {
+        _errorReporter.reportErrorForNode(
+            StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE, expression);
+      } else {
+        _errorReporter.reportErrorForNode(
+            StaticTypeWarningCode.NON_BOOL_NEGATION_EXPRESSION, expression);
+      }
     }
   }
 
@@ -4677,8 +4688,6 @@
    * Check for illegal derefences of nullables, ie, "unchecked" usages of
    * nullable values. Note that *any* usage of a null value is an "unchecked"
    * usage, because proper checks will promote the type to a non-nullable value.
-   *
-   * See [StaticWarningCode.UNCHECKED_USE_OF_NULLABLE_VALUE]
    */
   bool _checkForNullableDereference(Expression expression) {
     if (expression == null ||
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 91657b9..3e549d1 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -475,7 +475,7 @@
   @override
   void visitFunctionExpression(FunctionExpression node) {
     if (node.parent is! FunctionDeclaration) {
-      _checkForMissingReturn(null, node.body, node.element, node);
+      _checkForMissingReturn(null, node.body, node.declaredElement, node);
     }
     super.visitFunctionExpression(node);
   }
@@ -3396,6 +3396,13 @@
       LibraryElement coreLibrary, LibraryElement asyncLibrary)
       : super(coreLibrary, asyncLibrary);
 
+  /// Return a type provider initialized from the same library elements as the
+  /// [baseProvider].
+  factory NonNullableTypeProvider.from(TypeProvider baseProvider) {
+    return NonNullableTypeProvider(baseProvider.boolType.element.library,
+        baseProvider.streamType.element.library);
+  }
+
   @override
   InterfaceType _getType(Namespace namespace, String typeName) {
     InterfaceType type = super._getType(namespace, typeName);
@@ -7413,6 +7420,13 @@
     _initializeFrom(coreLibrary, asyncLibrary);
   }
 
+  /// Return a type provider initialized from the same library elements as the
+  /// [baseProvider].
+  factory TypeProviderImpl.from(TypeProvider baseProvider) {
+    return TypeProviderImpl(baseProvider.boolType.element.library,
+        baseProvider.streamType.element.library);
+  }
+
   @override
   InterfaceType get boolType => _boolType;