Index: pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
index b3ec3eb61a30dffadb3b6a2dc1be868cfc9ee549..9ff7ec1b41f6c9ecea3f361e8b9c99038f35a0dc 100644 |
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart |
@@ -811,7 +811,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
Expression target = node.realTarget; |
if (target != null) { |
DartType targetType = target.bestType; |
- if (_isAsyncFutureType(targetType)) { |
+ if (targetType.isDartAsyncFuture) { |
// Future.then(closure) return type is: |
// 1) the returned Future type, if the closure returns a Future; |
// 2) Future<valueType>, if the closure returns a value. |
@@ -1419,11 +1419,23 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
// TODO(brianwilkerson) Determine whether this can still happen. |
staticType2 = _dynamicType; |
} |
+ |
DartType staticType = |
- _typeSystem.getLeastUpperBound(staticType1, staticType2); |
- if (staticType == null) { |
- staticType = _dynamicType; |
+ _typeSystem.getLeastUpperBound(staticType1, staticType2) ?? |
+ _dynamicType; |
+ |
+ // TODO(jmesserly): this behavior needs to be specified. |
+ // The goal here is to avoid LUB concluding Object when we already had a |
+ // valid FutureOr<T> as the downward context type for a conditional. |
Leaf
2017/01/24 21:56:26
I'm not keen on putting this in just as a hack for
Jennifer Messerly
2017/01/25 00:33:35
Done.
|
+ if (_strongMode && staticType.isObject) { |
Paul Berry
2017/01/24 17:45:13
Why put this logic here and not in _typeSystem.get
Jennifer Messerly
2017/01/24 18:58:20
yeah ... the problem tho is we have two implementa
Paul Berry
2017/01/24 19:19:09
Agreed. It's really unfortunate that we have two
Paul Berry
2017/01/24 20:14:50
Ack! I just re-read this and realized that it onl
Jennifer Messerly
2017/01/25 00:33:35
ahhh gotcha :)
yeah that explains why a lot of th
|
+ DartType context = InferenceContext.getContext(node); |
+ if (context != null && context.isDartAsyncFutureOr && |
+ _typeSystem.isSubtypeOf(staticType1, context) && |
+ _typeSystem.isSubtypeOf(staticType2, context)) { |
+ staticType = context; |
+ } |
} |
+ |
_recordStaticType(node, staticType); |
DartType propagatedType1 = expr1.propagatedType; |
DartType propagatedType2 = expr2.propagatedType; |
@@ -1520,6 +1532,9 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
: _typeProvider.iterableType; |
return genericType.instantiate(<DartType>[type]); |
} else if (body.isAsynchronous) { |
+ if (type.isDartAsyncFutureOr) { |
Paul Berry
2017/01/24 17:45:13
I'm worried that this behavior hasn't been impleme
Jennifer Messerly
2017/01/24 18:58:20
this is the same logic that was below, on line 208
Paul Berry
2017/01/24 19:19:09
Ok, I didn't realize this was preexisting behavior
|
+ type = (type as InterfaceType).typeArguments[0]; |
+ } |
return _typeProvider.futureType |
.instantiate(<DartType>[type.flattenFutures(_typeSystem)]); |
} else { |
@@ -1962,44 +1977,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
argTypes.add(argumentList.arguments[i].staticType); |
} |
} |
- |
- // Special case Future<T>.then upwards inference. It has signature: |
- // |
- // <S>(T -> (S | Future<S>)) -> Future<S> |
- // |
- // Based on the first argument type, we'll pick one of these signatures: |
- // |
- // <S>(T -> S) -> Future<S> |
- // <S>(T -> Future<S>) -> Future<S> |
- // |
- // ... and finish the inference using that. |
- if (argTypes.isNotEmpty && _resolver.isFutureThen(fnType.element)) { |
- var firstArgType = argTypes[0]; |
- var firstParamType = paramTypes[0] as FunctionType; |
- if (firstArgType is FunctionType) { |
- var argReturnType = firstArgType.returnType; |
- // Skip the inference if we have the top type. It can only lead to |
- // worse inference. For example, this happens when the lambda returns |
- // S or Future<S> in a conditional. |
- if (!argReturnType.isObject && !argReturnType.isDynamic) { |
- DartType paramReturnType = fnType.typeFormals[0].type; |
- if (_resolver.isSubtypeOfFuture(argReturnType)) { |
- // Given an argument of (T) -> Future<S>, instantiate with <S> |
- paramReturnType = |
- _typeProvider.futureType.instantiate([paramReturnType]); |
- } |
- |
- // Adjust the expected parameter type to have this return type. |
- var function = new FunctionElementImpl(firstParamType.name, -1) |
- ..isSynthetic = true |
- ..shareParameters(firstParamType.parameters) |
- ..returnType = paramReturnType; |
- function.type = new FunctionTypeImpl(function); |
- // Use this as the expected 1st parameter type. |
- paramTypes[0] = function.type; |
- } |
- } |
- } |
return ts.inferGenericFunctionCall(fnType, paramTypes, argTypes, |
fnType.returnType, InferenceContext.getContext(node), |
errorReporter: _resolver.errorReporter, errorNode: errorNode); |
@@ -2081,12 +2058,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
// * we also normalize bottom to dynamic here. |
if (_strongMode && (computedType.isBottom || computedType.isDynamic)) { |
DartType contextType = InferenceContext.getContext(body); |
- if (contextType is FutureUnionType) { |
- // TODO(jmesserly): can we do something better here? |
- computedType = body.isAsynchronous ? contextType.type : _dynamicType; |
- } else { |
- computedType = contextType ?? _dynamicType; |
- } |
+ computedType = contextType ?? _dynamicType; |
recordInference = !computedType.isDynamic; |
} |
@@ -2221,23 +2193,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> { |
} |
/** |
- * Return `true` if the given [Type] is the `Future` form the 'dart:async' |
- * library. |
- */ |
- bool _isAsyncFutureType(DartType type) => |
- type is InterfaceType && |
- type.name == "Future" && |
- _isAsyncLibrary(type.element.library); |
- |
- /** |
- * Return `true` if the given library is the 'dart:async' library. |
- * |
- * @param library the library being tested |
- * @return `true` if the library is 'dart:async' |
- */ |
- bool _isAsyncLibrary(LibraryElement library) => library.name == "dart.async"; |
- |
- /** |
* Return `true` if the given library is the 'dart:html' library. |
* |
* @param library the library being tested |