| 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 7aaa2fa07dc9fdd28878277b7a2177ad5d536c8e..e67d09669df01d823329161503dbc508d9074782 100644
|
| --- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
|
| +++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
|
| @@ -282,11 +282,11 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
| // TODO(brianwilkerson) Determine whether this can still happen.
|
| staticExpressionType = _dynamicType;
|
| }
|
| - DartType staticType = flattenFutures(_typeProvider, staticExpressionType);
|
| + DartType staticType = staticExpressionType.flattenFutures(_typeSystem);
|
| _recordStaticType(node, staticType);
|
| DartType propagatedExpressionType = node.expression.propagatedType;
|
| DartType propagatedType =
|
| - flattenFutures(_typeProvider, propagatedExpressionType);
|
| + propagatedExpressionType?.flattenFutures(_typeSystem);
|
| _resolver.recordPropagatedTypeIfBetter(node, propagatedType);
|
| return null;
|
| }
|
| @@ -735,7 +735,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
| // Check for special cases.
|
| bool needPropagatedType = true;
|
| String methodName = methodNameNode.name;
|
| - if (methodName == "then") {
|
| + if (!_strongMode && methodName == "then") {
|
| Expression target = node.realTarget;
|
| if (target != null) {
|
| DartType targetType = target.bestType;
|
| @@ -754,16 +754,10 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
| _computePropagatedReturnType(closureExpr.element);
|
| if (returnType != null) {
|
| // prepare the type of the returned Future
|
| - InterfaceTypeImpl newFutureType;
|
| - if (_isAsyncFutureType(returnType)) {
|
| - newFutureType = returnType as InterfaceTypeImpl;
|
| - } else {
|
| - InterfaceType futureType = targetType as InterfaceType;
|
| - newFutureType = new InterfaceTypeImpl(futureType.element);
|
| - newFutureType.typeArguments = <DartType>[returnType];
|
| - }
|
| + InterfaceType newFutureType = _typeProvider.futureType
|
| + .substitute4([returnType.flattenFutures(_typeSystem)]);
|
| // set the 'then' invocation type
|
| - _recordPropagatedType(node, newFutureType);
|
| + _resolver.recordPropagatedTypeIfBetter(node, newFutureType);
|
| needPropagatedType = false;
|
| return null;
|
| }
|
| @@ -1503,7 +1497,7 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
| }
|
| if (body.isAsynchronous) {
|
| return _typeProvider.futureType
|
| - .substitute4(<DartType>[flattenFutures(_typeProvider, type)]);
|
| + .substitute4(<DartType>[type.flattenFutures(_typeSystem)]);
|
| } else {
|
| return type;
|
| }
|
| @@ -2120,47 +2114,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| - * Implements the function "flatten" defined in the spec:
|
| - *
|
| - * If T = Future<S> then flatten(T) = flatten(S).
|
| - *
|
| - * Otherwise if T <: Future then let S be a type such that T << Future<S>
|
| - * and for all R, if T << Future<R> then S << R. Then flatten(T) = S.
|
| - *
|
| - * In any other circumstance, flatten(T) = T.
|
| - */
|
| - static DartType flattenFutures(TypeProvider typeProvider, DartType type) {
|
| - if (type is InterfaceType) {
|
| - // Implement the case: "If T = Future<S> then flatten(T) = flatten(S)."
|
| - if (type.element == typeProvider.futureType.element &&
|
| - type.typeArguments.length > 0) {
|
| - return flattenFutures(typeProvider, type.typeArguments[0]);
|
| - }
|
| -
|
| - // Implement the case: "Otherwise if T <: Future then let S be a type
|
| - // such that T << Future<S> and for all R, if T << Future<R> then S << R.
|
| - // Then flatten(T) = S."
|
| - //
|
| - // In other words, given the set of all types R such that T << Future<R>,
|
| - // let S be the most specific of those types, if any such S exists.
|
| - //
|
| - // Since we only care about the most specific type, it is sufficent to
|
| - // look at the types appearing as a parameter to Future in the type
|
| - // hierarchy of T. We don't need to consider the supertypes of those
|
| - // types, since they are by definition less specific.
|
| - List<DartType> candidateTypes =
|
| - _searchTypeHierarchyForFutureParameters(typeProvider, type);
|
| - DartType flattenResult = _findMostSpecificType(candidateTypes);
|
| - if (flattenResult != null) {
|
| - return flattenResult;
|
| - }
|
| - }
|
| -
|
| - // Implement the case: "In any other circumstance, flatten(T) = T."
|
| - return type;
|
| - }
|
| -
|
| - /**
|
| * Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
|
| * implement those tags.
|
| *
|
| @@ -2228,88 +2181,6 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
|
| map["video"] = "VideoElement";
|
| return map;
|
| }
|
| -
|
| - /**
|
| - * If there is a single type which is at least as specific as all of the
|
| - * types in [types], return it. Otherwise return `null`.
|
| - */
|
| - static DartType _findMostSpecificType(List<DartType> types) {
|
| - // The << relation ("more specific than") is a partial ordering on types,
|
| - // so to find the most specific type of a set, we keep a bucket of the most
|
| - // specific types seen so far such that no type in the bucket is more
|
| - // specific than any other type in the bucket.
|
| - List<DartType> bucket = <DartType>[];
|
| -
|
| - // Then we consider each type in turn.
|
| - for (DartType type in types) {
|
| - // If any existing type in the bucket is more specific than this type,
|
| - // then we can ignore this type.
|
| - if (bucket.any((DartType t) => t.isMoreSpecificThan(type))) {
|
| - continue;
|
| - }
|
| - // Otherwise, we need to add this type to the bucket and remove any types
|
| - // that are less specific than it.
|
| - bool added = false;
|
| - int i = 0;
|
| - while (i < bucket.length) {
|
| - if (type.isMoreSpecificThan(bucket[i])) {
|
| - if (added) {
|
| - if (i < bucket.length - 1) {
|
| - bucket[i] = bucket.removeLast();
|
| - } else {
|
| - bucket.removeLast();
|
| - }
|
| - } else {
|
| - bucket[i] = type;
|
| - i++;
|
| - added = true;
|
| - }
|
| - } else {
|
| - i++;
|
| - }
|
| - }
|
| - if (!added) {
|
| - bucket.add(type);
|
| - }
|
| - }
|
| -
|
| - // Now that we are finished, if there is exactly one type left in the
|
| - // bucket, it is the most specific type.
|
| - if (bucket.length == 1) {
|
| - return bucket[0];
|
| - }
|
| -
|
| - // Otherwise, there is no single type that is more specific than the
|
| - // others.
|
| - return null;
|
| - }
|
| -
|
| - /**
|
| - * Given a seed type [type], search its class hierarchy for types of the form
|
| - * Future<R>, and return a list of the resulting R's.
|
| - */
|
| - static List<DartType> _searchTypeHierarchyForFutureParameters(
|
| - TypeProvider typeProvider, InterfaceType type) {
|
| - List<DartType> result = <DartType>[];
|
| - HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
|
| - void recurse(InterfaceType type) {
|
| - if (type.element == typeProvider.futureType.element &&
|
| - type.typeArguments.length > 0) {
|
| - result.add(type.typeArguments[0]);
|
| - }
|
| - if (visitedClasses.add(type.element)) {
|
| - if (type.superclass != null) {
|
| - recurse(type.superclass);
|
| - }
|
| - for (InterfaceType interface in type.interfaces) {
|
| - recurse(interface);
|
| - }
|
| - visitedClasses.remove(type.element);
|
| - }
|
| - }
|
| - recurse(type);
|
| - return result;
|
| - }
|
| }
|
|
|
| class _StaticTypeAnalyzer_computePropagatedReturnTypeOfFunction
|
|
|