Index: pkg/analyzer/lib/src/generated/type_system.dart |
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart |
index e7d747e1f5244e0e7857aff3f33ba60301b77ddf..b19ae14f90edc13ed08740c472c8980f39d4def1 100644 |
--- a/pkg/analyzer/lib/src/generated/type_system.dart |
+++ b/pkg/analyzer/lib/src/generated/type_system.dart |
@@ -7,6 +7,7 @@ library analyzer.src.generated.type_system; |
import 'dart:collection'; |
import 'dart:math' as math; |
+import 'package:analyzer/dart/ast/ast.dart' show AstNode; |
import 'package:analyzer/dart/ast/token.dart' show TokenType; |
import 'package:analyzer/dart/element/element.dart'; |
import 'package:analyzer/dart/element/type.dart'; |
@@ -14,6 +15,8 @@ import 'package:analyzer/src/dart/element/element.dart'; |
import 'package:analyzer/src/dart/element/type.dart'; |
import 'package:analyzer/src/generated/engine.dart' |
show AnalysisContext, AnalysisOptionsImpl; |
+import 'package:analyzer/src/generated/error.dart' |
+ show ErrorCode, ErrorReporter, StrongModeCode; |
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; |
import 'package:analyzer/src/generated/utilities_general.dart' |
@@ -248,6 +251,9 @@ class StrongTypeSystemImpl extends TypeSystem { |
// |
// It would be safe to return a partial solution here, but the user |
// experience may be better if we simply do not infer in this case. |
+ // |
+ // TODO(jmesserly): this heuristic is old. Maybe we should we issue the |
+ // inference error? |
return resultType ?? fnType; |
} |
@@ -272,7 +278,9 @@ class StrongTypeSystemImpl extends TypeSystem { |
FunctionType fnType, |
List<DartType> correspondingParameterTypes, |
List<DartType> argumentTypes, |
- DartType returnContextType) { |
+ DartType returnContextType, |
+ {ErrorReporter errorReporter, |
+ AstNode errorNode}) { |
if (fnType.typeFormals.isEmpty) { |
return fnType; |
} |
@@ -305,7 +313,7 @@ class StrongTypeSystemImpl extends TypeSystem { |
argumentTypes[i], correspondingParameterTypes[i]); |
} |
- return inferringTypeSystem._infer(fnType); |
+ return inferringTypeSystem._infer(fnType, errorReporter, errorNode); |
} |
/** |
@@ -1371,7 +1379,8 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { |
/// Given the constraints that were given by calling [isSubtypeOf], find the |
/// instantiation of the generic function that satisfies these constraints. |
- FunctionType _infer(FunctionType fnType) { |
+ FunctionType _infer(FunctionType fnType, |
+ [ErrorReporter errorReporter, AstNode errorNode]) { |
List<TypeParameterType> fnTypeParams = |
TypeParameterTypeImpl.getTypes(fnType.typeFormals); |
@@ -1423,15 +1432,39 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { |
new _TypeParameterVariance.from(typeParam, fnType.returnType); |
_TypeParameterBound bound = _bounds[typeParam]; |
- inferredTypes[i] = |
- variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower; |
+ DartType lowerBound = bound.lower; |
+ DartType upperBound = bound.upper; |
// See if the bounds can be satisfied. |
- if (bound.upper.isBottom || |
- !_typeSystem.isSubtypeOf(bound.lower, bound.upper)) { |
- // Inference failed. Bail. |
- return null; |
+ // TODO(jmesserly): also we should have an error for unconstrained type |
+ // parameters, rather than silently inferring dynamic. |
+ if (upperBound.isBottom || |
+ !_typeSystem.isSubtypeOf(lowerBound, upperBound)) { |
+ // Inference failed. |
+ if (errorReporter == null) { |
+ return null; |
+ } |
+ errorReporter.reportErrorForNode(StrongModeCode.COULD_NOT_INFER, |
+ errorNode, [typeParam, lowerBound, upperBound]); |
+ |
+ // To make the errors more useful, we swap the normal heuristic. |
+ // |
+ // The normal heuristic prefers using the argument types (upwards |
+ // inference, lower bound) to choose a tighter type. |
+ // |
+ // Here we want to prefer the return context type, so we can put the |
+ // blame on the arguments to the function. That will result in narrow |
+ // error spans. But ultimately it's just a heuristic, as the code is |
+ // already erroneous. |
+ // |
+ // (we may adjust the normal heuristic too, once upwards+downwards |
+ // inference are fully integrated, to prefer downwards info). |
+ lowerBound = bound.upper; |
+ upperBound = bound.lower; |
} |
+ |
+ inferredTypes[i] = |
+ variance.passedIn || lowerBound.isBottom ? upperBound : lowerBound; |
} |
// Return the instantiated type. |