Chromium Code Reviews| 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 |