| Index: pkg/analyzer/lib/src/task/strong/checker.dart
|
| diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
|
| index a67251e7905f1279f3841bb9da968481d640e5a6..635175cc5ab058071d2b2e21c95cb5b718416bd4 100644
|
| --- a/pkg/analyzer/lib/src/task/strong/checker.dart
|
| +++ b/pkg/analyzer/lib/src/task/strong/checker.dart
|
| @@ -11,6 +11,7 @@ import 'package:analyzer/dart/ast/ast.dart';
|
| import 'package:analyzer/dart/ast/visitor.dart';
|
| import 'package:analyzer/dart/element/element.dart';
|
| import 'package:analyzer/dart/element/type.dart';
|
| +import 'package:analyzer/src/dart/element/element.dart';
|
| import 'package:analyzer/src/dart/element/type.dart';
|
| import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
|
| import 'package:analyzer/src/generated/scanner.dart' show Token, TokenType;
|
| @@ -565,7 +566,7 @@ class CodeChecker extends RecursiveAstVisitor {
|
| }
|
|
|
| StaticInfo _checkAssignment(Expression expr, DartType toT) {
|
| - final fromT = expr.staticType ?? DynamicTypeImpl.instance;
|
| + final fromT = _getStaticType(expr);
|
| final Coercion c = _coerceTo(fromT, toT);
|
| if (c is Identity) return null;
|
| if (c is CoercionError) return new StaticTypeError(rules, expr, toT);
|
| @@ -778,7 +779,57 @@ class CodeChecker extends RecursiveAstVisitor {
|
| }
|
|
|
| DartType _getStaticType(Expression expr) {
|
| - return expr.staticType ?? DynamicTypeImpl.instance;
|
| + DartType t = expr.staticType ?? DynamicTypeImpl.instance;
|
| +
|
| + // Remove fuzzy arrow if possible.
|
| + if (t is FunctionType && StaticInfo.isKnownFunction(expr)) {
|
| + t = _removeFuzz(t);
|
| + }
|
| +
|
| + return t;
|
| + }
|
| +
|
| + /// Remove "fuzzy arrow" in this function type.
|
| + ///
|
| + /// Normally we treat dynamically typed parameters as bottom for function
|
| + /// types. This allows type tests such as `if (f is SingleArgFunction)`.
|
| + /// It also requires a dynamic check on the parameter type to call these
|
| + /// functions.
|
| + ///
|
| + /// When we convert to a strict arrow, dynamically typed parameters become
|
| + /// top. This is safe to do for known functions, like top-level or local
|
| + /// functions and static methods. Those functions must already be essentially
|
| + /// treating dynamic as top.
|
| + ///
|
| + /// Only the outer-most arrow can be strict. Any others must be fuzzy, because
|
| + /// we don't know what function value will be passed there.
|
| + FunctionType _removeFuzz(FunctionType t) {
|
| + bool foundFuzz = false;
|
| + List<ParameterElement> parameters = <ParameterElement>[];
|
| + for (ParameterElement p in t.parameters) {
|
| + ParameterElement newP = _removeParameterFuzz(p);
|
| + parameters.add(newP);
|
| + if (p != newP) foundFuzz = true;
|
| + }
|
| + if (!foundFuzz) {
|
| + return t;
|
| + }
|
| +
|
| + FunctionElementImpl function = new FunctionElementImpl("", -1);
|
| + function.synthetic = true;
|
| + function.returnType = t.returnType;
|
| + function.shareTypeParameters(t.typeFormals);
|
| + function.shareParameters(parameters);
|
| + return function.type = new FunctionTypeImpl(function);
|
| + }
|
| +
|
| + /// Removes fuzzy arrow, see [_removeFuzz].
|
| + ParameterElement _removeParameterFuzz(ParameterElement p) {
|
| + if (p.type.isDynamic) {
|
| + return new ParameterElementImpl.synthetic(
|
| + p.name, typeProvider.objectType, p.parameterKind);
|
| + }
|
| + return p;
|
| }
|
|
|
| /// Given an expression, return its type assuming it is
|
|
|