Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/type_system.dart |
| diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart |
| index b19ae14f90edc13ed08740c472c8980f39d4def1..dfc52820409976ae8901e03aae1acc1100fe7d89 100644 |
| --- a/pkg/analyzer/lib/src/generated/type_system.dart |
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart |
| @@ -16,15 +16,135 @@ import 'package:analyzer/src/dart/element/type.dart'; |
| import 'package:analyzer/src/generated/engine.dart' |
| show AnalysisContext, AnalysisOptionsImpl; |
| import 'package:analyzer/src/generated/error.dart' |
| - show ErrorCode, ErrorReporter, StrongModeCode; |
|
Brian Wilkerson
2016/09/09 15:52:03
This is the only change I made in this file. The r
|
| + show ErrorReporter, StrongModeCode; |
| import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; |
| import 'package:analyzer/src/generated/utilities_general.dart' |
| show JenkinsSmiHash; |
| +bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
| + return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
| +} |
| + |
| +bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
| + // TODO(leafp): Document the rules in play here |
| + return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
| +} |
| + |
| typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
| /** |
| + * A special union type of `Future<T> | T` used for Strong Mode inference. |
| + */ |
| +class FutureUnionType extends TypeImpl { |
| + // TODO(jmesserly): a Set would be better. |
| + // |
| + // For now we know `Future<T> | T` is the only valid use, so we can rely on |
| + // the order, which simplifies some things. |
| + // |
| + // This will need clean up before this can function as a real union type. |
| + final List<DartType> _types; |
| + |
| + /** |
| + * Creates a union of `Future<T> | T`. |
| + */ |
| + FutureUnionType._(DartType type, TypeProvider provider, TypeSystem system) |
| + : _types = [ |
| + provider.futureType.instantiate([type]), |
| + type |
| + ], |
| + super(null, null); |
| + |
| + DartType get futureOfType => _types[0]; |
| + |
| + @override |
| + int get hashCode { |
| + int hash = 0; |
| + for (var t in types) { |
| + hash = JenkinsSmiHash.combine(hash, t.hashCode); |
| + } |
| + return JenkinsSmiHash.finish(hash); |
| + } |
| + |
| + DartType get type => _types[1]; |
| + |
| + Iterable<DartType> get types => _types; |
| + |
| + @override |
| + bool operator ==(Object obj) { |
| + if (obj is FutureUnionType) { |
| + if (identical(obj, this)) return true; |
| + return types.length == obj.types.length && |
| + types.toSet().containsAll(obj.types); |
| + } |
| + return false; |
| + } |
| + |
| + @override |
| + void appendTo(StringBuffer buffer) { |
| + buffer.write('('); |
| + for (int i = 0; i < _types.length; i++) { |
| + if (i != 0) { |
| + buffer.write(' | '); |
| + } |
| + (_types[i] as TypeImpl).appendTo(buffer); |
| + } |
| + buffer.write(')'); |
| + } |
| + |
| + @override |
| + bool isMoreSpecificThan(DartType type, |
| + [bool withDynamic = false, Set<Element> visitedElements]) => |
| + throw new UnsupportedError( |
| + 'Future unions are not part of the Dart 1 type system'); |
| + |
| + @override |
| + TypeImpl pruned(List<FunctionTypeAliasElement> prune) => |
| + throw new UnsupportedError('Future unions are not substituted'); |
| + |
| + @override |
| + DartType substitute2(List<DartType> args, List<DartType> params, |
| + [List<FunctionTypeAliasElement> prune]) => |
| + throw new UnsupportedError('Future unions are not used in typedefs'); |
| + |
| + /** |
| + * Creates a union of `T | Future<T>`, unless `T` is already a future or a |
| + * future-union, in which case it simply returns `T`. |
| + * |
| + * Conceptually this is used as the inverse of the `flatten(T)` operation, |
| + * defined as: |
| + * |
| + * - `flatten(Future<T>) -> T` |
| + * - `flatten(T) -> T` |
| + * |
| + * Thus the inverse will give us `T | Future<T>`. |
| + * |
| + * If [type] is top (dynamic or Object) then the resulting union type is |
| + * equivalent to top, so we simply return it. |
| + * |
| + * For a similar reason `Future<T> | Future<Future<T>>` is equivalent to just |
| + * `Future<T>`, so we return it. Note that it is not possible to get a |
| + * `Future<T>` as a result of `flatten`, so a this case likely indicates a |
| + * type error in the code, but it will be reported elsewhere. |
| + */ |
| + static DartType from( |
| + DartType type, TypeProvider provider, TypeSystem system) { |
| + if (_isTop(type)) { |
| + return type; |
| + } |
| + if (!identical(type, type.flattenFutures(system))) { |
| + // As noted above, this most likely represents erroneous input. |
| + return type; |
| + } |
| + |
| + if (type is FutureUnionType) { |
| + return type; |
| + } |
| + return new FutureUnionType._(type, provider, system); |
| + } |
| +} |
| + |
| +/** |
| * Implementation of [TypeSystem] using the strong mode rules. |
| * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md |
| */ |
| @@ -176,6 +296,22 @@ class StrongTypeSystemImpl extends TypeSystem { |
| } |
| /** |
| + * Compute the least supertype of [type], which is known to be an interface |
| + * type. |
| + * |
| + * In the event that the algorithm fails (which might occur due to a bug in |
| + * the analyzer), `null` is returned. |
| + */ |
| + DartType getLeastNullableSupertype(InterfaceType type) { |
| + // compute set of supertypes |
| + List<InterfaceType> s = InterfaceTypeImpl |
| + .computeSuperinterfaceSet(type) |
| + .where(isNullableType) |
| + .toList(); |
| + return InterfaceTypeImpl.computeTypeAtMaxUniqueDepth(s); |
| + } |
| + |
| + /** |
| * Compute the least upper bound of two types. |
| */ |
| @override |
| @@ -195,22 +331,6 @@ class StrongTypeSystemImpl extends TypeSystem { |
| } |
| /** |
| - * Compute the least supertype of [type], which is known to be an interface |
| - * type. |
| - * |
| - * In the event that the algorithm fails (which might occur due to a bug in |
| - * the analyzer), `null` is returned. |
| - */ |
| - DartType getLeastNullableSupertype(InterfaceType type) { |
| - // compute set of supertypes |
| - List<InterfaceType> s = InterfaceTypeImpl |
| - .computeSuperinterfaceSet(type) |
| - .where(isNullableType) |
| - .toList(); |
| - return InterfaceTypeImpl.computeTypeAtMaxUniqueDepth(s); |
| - } |
| - |
| - /** |
| * Given a generic function type `F<T0, T1, ... Tn>` and a context type C, |
| * infer an instantiation of F, such that `F<S0, S1, ..., Sn>` <: C. |
| * |
| @@ -434,6 +554,18 @@ class StrongTypeSystemImpl extends TypeSystem { |
| @override |
| bool isMoreSpecificThan(DartType t1, DartType t2) => isSubtypeOf(t1, t2); |
| + /// Check if [type] is in a set of preselected non-nullable types. |
| + /// [FunctionType]s are always nullable. |
| + bool isNonNullableType(DartType type) { |
| + return !isNullableType(type); |
| + } |
| + |
| + /// Opposite of [isNonNullableType]. |
| + bool isNullableType(DartType type) { |
| + return type is FunctionType || |
| + !nonnullableTypes.contains(_getTypeFullyQualifiedName(type)); |
| + } |
| + |
| @override |
| bool isSubtypeOf(DartType leftType, DartType rightType) { |
| return _isSubtypeOf(leftType, rightType, null); |
| @@ -596,6 +728,12 @@ class StrongTypeSystemImpl extends TypeSystem { |
| TypeProvider provider, DartType f, DartType g) => |
| getGreatestLowerBound(provider, f, g, dynamicIsBottom: true); |
| + /// Given a type return its name prepended with the URI to its containing |
| + /// library and separated by a comma. |
| + String _getTypeFullyQualifiedName(DartType type) { |
| + return "${type?.element?.library?.identifier},$type"; |
| + } |
| + |
| /** |
| * Guard against loops in the class hierarchy |
| */ |
| @@ -821,24 +959,6 @@ class StrongTypeSystemImpl extends TypeSystem { |
| return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType); |
| } |
| - /// Check if [type] is in a set of preselected non-nullable types. |
| - /// [FunctionType]s are always nullable. |
| - bool isNonNullableType(DartType type) { |
| - return !isNullableType(type); |
| - } |
| - |
| - /// Opposite of [isNonNullableType]. |
| - bool isNullableType(DartType type) { |
| - return type is FunctionType || |
| - !nonnullableTypes.contains(_getTypeFullyQualifiedName(type)); |
| - } |
| - |
| - /// Given a type return its name prepended with the URI to its containing |
| - /// library and separated by a comma. |
| - String _getTypeFullyQualifiedName(DartType type) { |
| - return "${type?.element?.library?.identifier},$type"; |
| - } |
| - |
| /** |
| * This currently just implements a simple least upper bound to |
| * handle some common cases. It also avoids some termination issues |
| @@ -1618,123 +1738,3 @@ class _TypeParameterVariance { |
| } |
| } |
| } |
| - |
| -/** |
| - * A special union type of `Future<T> | T` used for Strong Mode inference. |
| - */ |
| -class FutureUnionType extends TypeImpl { |
| - // TODO(jmesserly): a Set would be better. |
| - // |
| - // For now we know `Future<T> | T` is the only valid use, so we can rely on |
| - // the order, which simplifies some things. |
| - // |
| - // This will need clean up before this can function as a real union type. |
| - final List<DartType> _types; |
| - |
| - /** |
| - * Creates a union of `Future<T> | T`. |
| - */ |
| - FutureUnionType._(DartType type, TypeProvider provider, TypeSystem system) |
| - : _types = [ |
| - provider.futureType.instantiate([type]), |
| - type |
| - ], |
| - super(null, null); |
| - |
| - DartType get futureOfType => _types[0]; |
| - |
| - DartType get type => _types[1]; |
| - |
| - Iterable<DartType> get types => _types; |
| - |
| - @override |
| - void appendTo(StringBuffer buffer) { |
| - buffer.write('('); |
| - for (int i = 0; i < _types.length; i++) { |
| - if (i != 0) { |
| - buffer.write(' | '); |
| - } |
| - (_types[i] as TypeImpl).appendTo(buffer); |
| - } |
| - buffer.write(')'); |
| - } |
| - |
| - @override |
| - int get hashCode { |
| - int hash = 0; |
| - for (var t in types) { |
| - hash = JenkinsSmiHash.combine(hash, t.hashCode); |
| - } |
| - return JenkinsSmiHash.finish(hash); |
| - } |
| - |
| - @override |
| - bool operator ==(Object obj) { |
| - if (obj is FutureUnionType) { |
| - if (identical(obj, this)) return true; |
| - return types.length == obj.types.length && |
| - types.toSet().containsAll(obj.types); |
| - } |
| - return false; |
| - } |
| - |
| - @override |
| - bool isMoreSpecificThan(DartType type, |
| - [bool withDynamic = false, Set<Element> visitedElements]) => |
| - throw new UnsupportedError( |
| - 'Future unions are not part of the Dart 1 type system'); |
| - |
| - @override |
| - TypeImpl pruned(List<FunctionTypeAliasElement> prune) => |
| - throw new UnsupportedError('Future unions are not substituted'); |
| - |
| - @override |
| - DartType substitute2(List<DartType> args, List<DartType> params, |
| - [List<FunctionTypeAliasElement> prune]) => |
| - throw new UnsupportedError('Future unions are not used in typedefs'); |
| - |
| - /** |
| - * Creates a union of `T | Future<T>`, unless `T` is already a future or a |
| - * future-union, in which case it simply returns `T`. |
| - * |
| - * Conceptually this is used as the inverse of the `flatten(T)` operation, |
| - * defined as: |
| - * |
| - * - `flatten(Future<T>) -> T` |
| - * - `flatten(T) -> T` |
| - * |
| - * Thus the inverse will give us `T | Future<T>`. |
| - * |
| - * If [type] is top (dynamic or Object) then the resulting union type is |
| - * equivalent to top, so we simply return it. |
| - * |
| - * For a similar reason `Future<T> | Future<Future<T>>` is equivalent to just |
| - * `Future<T>`, so we return it. Note that it is not possible to get a |
| - * `Future<T>` as a result of `flatten`, so a this case likely indicates a |
| - * type error in the code, but it will be reported elsewhere. |
| - */ |
| - static DartType from( |
| - DartType type, TypeProvider provider, TypeSystem system) { |
| - if (_isTop(type)) { |
| - return type; |
| - } |
| - if (!identical(type, type.flattenFutures(system))) { |
| - // As noted above, this most likely represents erroneous input. |
| - return type; |
| - } |
| - |
| - if (type is FutureUnionType) { |
| - return type; |
| - } |
| - return new FutureUnionType._(type, provider, system); |
| - } |
| -} |
| - |
| -bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
| - return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
| -} |
| - |
| -bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
| - // TODO(leafp): Document the rules in play here |
| - return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
| -} |