Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(681)

Unified Diff: pkg/analyzer/lib/src/generated/static_type_analyzer.dart

Issue 1023903002: Implement the new definition of flatten() from r44569 in analyzer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/resolver_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 3f38498cdacde08770f4b4f316159012ad132f37..af157bbbc2701b4d804c8f2b9afefb29ebe60d92 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -172,9 +172,8 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
/**
* The Dart Language Specification, 16.29 (Await Expressions):
*
- * Let flatten(T) = flatten(S) if T = Future<S>, and T otherwise. The
- * static type of [the expression "await e"] is flatten(T) where T is the
- * static type of e.
+ * The static type of [the expression "await e"] is flatten(T) where T is
+ * the static type of e.
*/
@override
Object visitAwaitExpression(AwaitExpression node) {
@@ -1740,15 +1739,43 @@ class StaticTypeAnalyzer extends SimpleAstVisitor<Object> {
}
/**
- * Implements the function "flatten" defined in the spec: "Let flatten(T) =
- * flatten(S) if T = Future<S>, and T otherwise."
+ * 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 &&
- type.element == typeProvider.futureType.element &&
- type.typeArguments.length > 0) {
- return flattenFutures(typeProvider, type.typeArguments[0]);
+ 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;
}
@@ -1820,6 +1847,88 @@ 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
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/resolver_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698