Fix the special casing of binary operators with primitive types when NNBD is enabled
Change-Id: I36f7f63b26eb3ea87efbe7af96d2134ea6402158
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/102020
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 14f6958..8eff525 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -41,6 +41,11 @@
final ResolverVisitor _resolver;
/**
+ * The feature set that should be used to resolve types.
+ */
+ final FeatureSet _featureSet;
+
+ /**
* The object providing access to the types defined by the language.
*/
TypeProvider _typeProvider;
@@ -72,16 +77,12 @@
TypePromotionManager _promoteManager;
/**
- * Whether NNBD is enabled for this compilation unit.
- */
- bool _nonNullableEnabled;
-
- /**
- * Initialize a newly created type analyzer.
+ * Initialize a newly created static type analyzer to analyze types for the
+ * [_resolver] based on the
*
* @param resolver the resolver driving this participant
*/
- StaticTypeAnalyzer(this._resolver, FeatureSet featureSet) {
+ StaticTypeAnalyzer(this._resolver, this._featureSet) {
_typeProvider = _resolver.typeProvider;
_typeSystem = _resolver.typeSystem;
_dynamicType = _typeProvider.dynamicType;
@@ -89,10 +90,14 @@
AnalysisOptionsImpl analysisOptions =
_resolver.definingLibrary.context.analysisOptions;
_strictInference = analysisOptions.strictInference;
- _nonNullableEnabled = featureSet.isEnabled(Feature.non_nullable);
}
/**
+ * Return `true` if NNBD is enabled for this compilation unit.
+ */
+ bool get _nonNullableEnabled => _featureSet.isEnabled(Feature.non_nullable);
+
+ /**
* Given a constructor name [node] and a type [type], record an inferred type
* for the constructor if in strong mode. This is used to fill in any
* inferred type parameters found by the resolver.
@@ -318,7 +323,8 @@
_getStaticType(node.leftHandSide, read: true),
operator,
node.rightHandSide.staticType,
- staticType);
+ staticType,
+ _featureSet);
_recordStaticType(node, staticType);
}
}
@@ -409,7 +415,8 @@
node.leftOperand.staticType,
node.operator.type,
node.rightOperand.staticType,
- staticType);
+ staticType,
+ _featureSet);
_recordStaticType(node, staticType);
}
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index a774f85..4ef1a61 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -5,6 +5,7 @@
import 'dart:collection';
import 'dart:math' as math;
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart' show AstNode;
import 'package:analyzer/dart/ast/token.dart' show Keyword, TokenType;
import 'package:analyzer/dart/element/element.dart';
@@ -648,7 +649,7 @@
@override
DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
- DartType rightType, DartType currentType) {
+ DartType rightType, DartType currentType, FeatureSet featureSet) {
if (leftType is TypeParameterType &&
leftType.element.bound == typeProvider.numType) {
if (rightType == leftType || rightType == typeProvider.intType) {
@@ -658,6 +659,9 @@
operator == TokenType.PLUS_EQ ||
operator == TokenType.MINUS_EQ ||
operator == TokenType.STAR_EQ) {
+ if (featureSet.isEnabled(Feature.non_nullable)) {
+ return promoteToNonNull(leftType as TypeImpl);
+ }
return leftType;
}
}
@@ -666,13 +670,16 @@
operator == TokenType.MINUS ||
operator == TokenType.STAR ||
operator == TokenType.SLASH) {
+ if (featureSet.isEnabled(Feature.non_nullable)) {
+ return promoteToNonNull(typeProvider.doubleType as TypeImpl);
+ }
return typeProvider.doubleType;
}
}
return currentType;
}
- return super
- .refineBinaryExpressionType(leftType, operator, rightType, currentType);
+ return super.refineBinaryExpressionType(
+ leftType, operator, rightType, currentType, featureSet);
}
@override
@@ -2088,16 +2095,22 @@
}
/**
- * Attempts to make a better guess for the type of a binary with the given
- * [operator], given that resolution has so far produced the [currentType].
+ * Determine the type of a binary expression with the given [operator] whose
+ * left operand has the type [leftType] and whose right operand has the type
+ * [rightType], given that resolution has so far produced the [currentType].
+ * The [featureSet] is used to determine whether any features that effect the
+ * computation have been enabled.
*/
DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
- DartType rightType, DartType currentType) {
+ DartType rightType, DartType currentType, FeatureSet featureSet) {
// bool
if (operator == TokenType.AMPERSAND_AMPERSAND ||
operator == TokenType.BAR_BAR ||
operator == TokenType.EQ_EQ ||
operator == TokenType.BANG_EQ) {
+ if (featureSet.isEnabled(Feature.non_nullable)) {
+ return promoteToNonNull(typeProvider.boolType as TypeImpl);
+ }
return typeProvider.boolType;
}
DartType intType = typeProvider.intType;
@@ -2113,6 +2126,9 @@
operator == TokenType.STAR_EQ) {
DartType doubleType = typeProvider.doubleType;
if (rightType == doubleType) {
+ if (featureSet.isEnabled(Feature.non_nullable)) {
+ return promoteToNonNull(doubleType as TypeImpl);
+ }
return doubleType;
}
}
@@ -2128,6 +2144,9 @@
operator == TokenType.STAR_EQ ||
operator == TokenType.TILDE_SLASH_EQ) {
if (rightType == intType) {
+ if (featureSet.isEnabled(Feature.non_nullable)) {
+ return promoteToNonNull(intType as TypeImpl);
+ }
return intType;
}
}
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 0708ecf..e451ec6 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -6,6 +6,7 @@
// refactored to fit into analyzer.
import 'dart:collection';
+import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_resolution_map.dart';
import 'package:analyzer/dart/ast/token.dart' show TokenType;
@@ -123,6 +124,8 @@
final AnalysisOptionsImpl _options;
_OverrideChecker _overrideChecker;
+ FeatureSet _featureSet;
+
bool _failure = false;
bool _hasImplicitCasts;
HashSet<ExecutableElement> _covariantPrivateMembers;
@@ -334,6 +337,7 @@
@override
void visitCompilationUnit(CompilationUnit node) {
+ _featureSet = node.featureSet;
_hasImplicitCasts = false;
_covariantPrivateMembers = new HashSet();
node.visitChildren(this);
@@ -733,7 +737,7 @@
var rhsType = _getExpressionType(expr.rightHandSide);
var lhsType = _getExpressionType(expr.leftHandSide);
var returnType = rules.refineBinaryExpressionType(
- lhsType, op, rhsType, functionType.returnType);
+ lhsType, op, rhsType, functionType.returnType, _featureSet);
// Check the argument for an implicit cast.
_checkImplicitCast(expr.rightHandSide, paramTypes[0], from: rhsType);
@@ -958,8 +962,8 @@
var functionType = element.type;
var rhsType = typeProvider.intType;
var lhsType = _getExpressionType(operand);
- var returnType = rules.refineBinaryExpressionType(
- lhsType, TokenType.PLUS, rhsType, functionType.returnType);
+ var returnType = rules.refineBinaryExpressionType(lhsType,
+ TokenType.PLUS, rhsType, functionType.returnType, _featureSet);
// Skip the argument check - `int` cannot be downcast.
//
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/equality_expressions_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/equality_expressions_test.dart
index c78c359..d0bf2ff 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/equality_expressions_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/equality_expressions_test.dart
@@ -40,12 +40,6 @@
@override
bool get typeToStringWithNullability => true;
-
- @failingTest
- @override
- test_simple() async {
- await super.test_simple();
- }
}
@reflectiveTest
@@ -71,10 +65,4 @@
@override
bool get typeToStringWithNullability => true;
-
- @failingTest
- @override
- test_simple() async {
- await super.test_simple();
- }
}
diff --git a/pkg/analyzer/test/src/dart/resolution/type_inference/logical_boolean_expressions_test.dart b/pkg/analyzer/test/src/dart/resolution/type_inference/logical_boolean_expressions_test.dart
index 3c2e6ae..7f26d21 100644
--- a/pkg/analyzer/test/src/dart/resolution/type_inference/logical_boolean_expressions_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/type_inference/logical_boolean_expressions_test.dart
@@ -40,12 +40,6 @@
@override
bool get typeToStringWithNullability => true;
-
- @failingTest
- @override
- test_simple() async {
- await super.test_simple();
- }
}
@reflectiveTest
@@ -71,10 +65,4 @@
@override
bool get typeToStringWithNullability => true;
-
- @failingTest
- @override
- test_simple() async {
- await super.test_simple();
- }
}