| Index: pkg/analyzer/lib/src/generated/resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
|
| index 91f49200bb8ba8c9299b6b07be71c78df2ecfde6..eece655cd05407e8e8272c2013139e7c23953036 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -6,8 +6,6 @@ library engine.resolver;
|
|
|
| import 'dart:collection';
|
|
|
| -import 'package:analyzer/src/generated/scanner.dart';
|
| -
|
| import 'ast.dart';
|
| import 'constant.dart';
|
| import 'element.dart';
|
| @@ -18,12 +16,16 @@ import 'error_verifier.dart';
|
| import 'html.dart' as ht;
|
| import 'java_core.dart';
|
| import 'java_engine.dart';
|
| +import 'scanner.dart';
|
| import 'scanner.dart' as sc;
|
| import 'sdk.dart' show DartSdk, SdkLibrary;
|
| import 'source.dart';
|
| import 'static_type_analyzer.dart';
|
| +import 'type_system.dart';
|
| import 'utilities_dart.dart';
|
|
|
| +export 'type_system.dart';
|
| +
|
| /**
|
| * Callback signature used by ImplicitConstructorBuilder to register
|
| * computations to be performed, and their dependencies. A call to this
|
| @@ -46,10 +48,6 @@ typedef TypeResolverVisitor TypeResolverVisitorFactory(
|
|
|
| typedef void VoidFunction();
|
|
|
| -typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
|
| -
|
| -typedef bool _SubtypeChecker<T>(T t1, T t2);
|
| -
|
| /**
|
| * Instances of the class `BestPracticesVerifier` traverse an AST structure looking for
|
| * violations of Dart best practices.
|
| @@ -12806,307 +12804,6 @@ abstract class ScopedVisitor extends UnifyingAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| - * Implementation of [TypeSystem] using the strong mode rules.
|
| - * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
|
| - */
|
| -class StrongTypeSystemImpl implements TypeSystem {
|
| - final _specTypeSystem = new TypeSystemImpl();
|
| -
|
| - StrongTypeSystemImpl();
|
| -
|
| - @override
|
| - DartType getLeastUpperBound(
|
| - TypeProvider typeProvider, DartType type1, DartType type2) {
|
| - // TODO(leafp): Implement a strong mode version of this.
|
| - return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
|
| - }
|
| -
|
| - // TODO(leafp): Document the rules in play here
|
| - @override
|
| - bool isAssignableTo(DartType fromType, DartType toType) {
|
| - // An actual subtype
|
| - if (isSubtypeOf(fromType, toType)) {
|
| - return true;
|
| - }
|
| -
|
| - // Don't allow implicit downcasts between function types
|
| - // and call method objects, as these will almost always fail.
|
| - if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
|
| - (toType is FunctionType && _getCallMethodType(fromType) != null)) {
|
| - return false;
|
| - }
|
| -
|
| - // If the subtype relation goes the other way, allow the implicit downcast.
|
| - // TODO(leafp): Emit warnings and hints for these in some way.
|
| - // TODO(leafp): Consider adding a flag to disable these? Or just rely on
|
| - // --warnings-as-errors?
|
| - if (isSubtypeOf(toType, fromType) ||
|
| - _specTypeSystem.isAssignableTo(toType, fromType)) {
|
| - // TODO(leafp): error if type is known to be exact (literal,
|
| - // instance creation).
|
| - // TODO(leafp): Warn on composite downcast.
|
| - // TODO(leafp): hint on object/dynamic downcast.
|
| - // TODO(leafp): Consider allowing assignment casts.
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - @override
|
| - bool isSubtypeOf(DartType leftType, DartType rightType) {
|
| - return _isSubtypeOf(leftType, rightType, null);
|
| - }
|
| -
|
| - FunctionType _getCallMethodType(DartType t) {
|
| - if (t is InterfaceType) {
|
| - return t.lookUpInheritedMethod("call")?.type;
|
| - }
|
| - return null;
|
| - }
|
| -
|
| - // Given a type t, if t is an interface type with a call method
|
| - // defined, return the function type for the call method, otherwise
|
| - // return null.
|
| - _GuardedSubtypeChecker<DartType> _guard(
|
| - _GuardedSubtypeChecker<DartType> check) {
|
| - return (DartType t1, DartType t2, Set<Element> visited) {
|
| - Element element = t1.element;
|
| - if (visited == null) {
|
| - visited = new HashSet<Element>();
|
| - }
|
| - if (element == null || !visited.add(element)) {
|
| - return false;
|
| - }
|
| - try {
|
| - return check(t1, t2, visited);
|
| - } finally {
|
| - visited.remove(element);
|
| - }
|
| - };
|
| - }
|
| -
|
| - bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
|
| - return (t.isDynamic && dynamicIsBottom) || t.isBottom;
|
| - }
|
| -
|
| - // Guard against loops in the class hierarchy
|
| - /**
|
| - * Check that [f1] is a subtype of [f2].
|
| - * [fuzzyArrows] indicates whether or not the f1 and f2 should be
|
| - * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
|
| - * as bottom).
|
| - */
|
| - bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
|
| - {bool fuzzyArrows: true}) {
|
| - final r1s = f1.normalParameterTypes;
|
| - final o1s = f1.optionalParameterTypes;
|
| - final n1s = f1.namedParameterTypes;
|
| - final r2s = f2.normalParameterTypes;
|
| - final o2s = f2.optionalParameterTypes;
|
| - final n2s = f2.namedParameterTypes;
|
| - final ret1 = f1.returnType;
|
| - final ret2 = f2.returnType;
|
| -
|
| - // A -> B <: C -> D if C <: A and
|
| - // either D is void or B <: D
|
| - if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
|
| - return false;
|
| - }
|
| -
|
| - // Reject if one has named and the other has optional
|
| - if (n1s.length > 0 && o2s.length > 0) {
|
| - return false;
|
| - }
|
| - if (n2s.length > 0 && o1s.length > 0) {
|
| - return false;
|
| - }
|
| -
|
| - // Rebind _isSubtypeOf for convenience
|
| - _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
|
| - _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
|
| -
|
| - // f2 has named parameters
|
| - if (n2s.length > 0) {
|
| - // Check that every named parameter in f2 has a match in f1
|
| - for (String k2 in n2s.keys) {
|
| - if (!n1s.containsKey(k2)) {
|
| - return false;
|
| - }
|
| - if (!parameterSubtype(n2s[k2], n1s[k2])) {
|
| - return false;
|
| - }
|
| - }
|
| - }
|
| - // If we get here, we either have no named parameters,
|
| - // or else the named parameters match and we have no optional
|
| - // parameters
|
| -
|
| - // If f1 has more required parameters, reject
|
| - if (r1s.length > r2s.length) {
|
| - return false;
|
| - }
|
| -
|
| - // If f2 has more required + optional parameters, reject
|
| - if (r2s.length + o2s.length > r1s.length + o1s.length) {
|
| - return false;
|
| - }
|
| -
|
| - // The parameter lists must look like the following at this point
|
| - // where rrr is a region of required, and ooo is a region of optionals.
|
| - // f1: rrr ooo ooo ooo
|
| - // f2: rrr rrr ooo
|
| - int rr = r1s.length; // required in both
|
| - int or = r2s.length - r1s.length; // optional in f1, required in f2
|
| - int oo = o2s.length; // optional in both
|
| -
|
| - for (int i = 0; i < rr; ++i) {
|
| - if (!parameterSubtype(r2s[i], r1s[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - for (int i = 0, j = rr; i < or; ++i, ++j) {
|
| - if (!parameterSubtype(r2s[j], o1s[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - for (int i = or, j = 0; i < oo; ++i, ++j) {
|
| - if (!parameterSubtype(o2s[j], o1s[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - bool _isInterfaceSubtypeOf(
|
| - InterfaceType i1, InterfaceType i2, Set<Element> visited) {
|
| - // Guard recursive calls
|
| - _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
|
| - _guard(_isInterfaceSubtypeOf);
|
| -
|
| - if (i1 == i2) {
|
| - return true;
|
| - }
|
| -
|
| - if (i1.element == i2.element) {
|
| - List<DartType> tArgs1 = i1.typeArguments;
|
| - List<DartType> tArgs2 = i2.typeArguments;
|
| -
|
| - assert(tArgs1.length == tArgs2.length);
|
| -
|
| - for (int i = 0; i < tArgs1.length; i++) {
|
| - DartType t1 = tArgs1[i];
|
| - DartType t2 = tArgs2[i];
|
| - if (!isSubtypeOf(t1, t2)) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
|
| - return true;
|
| - }
|
| -
|
| - if (i1.isObject) {
|
| - return false;
|
| - }
|
| -
|
| - if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
|
| - return true;
|
| - }
|
| -
|
| - for (final parent in i1.interfaces) {
|
| - if (guardedInterfaceSubtype(parent, i2, visited)) {
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - for (final parent in i1.mixins) {
|
| - if (guardedInterfaceSubtype(parent, i2, visited)) {
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
|
| - {bool dynamicIsBottom: false}) {
|
| - // Guard recursive calls
|
| - _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
|
| -
|
| - if (t1 == t2) {
|
| - return true;
|
| - }
|
| -
|
| - // The types are void, dynamic, bottom, interface types, function types
|
| - // and type parameters. We proceed by eliminating these different classes
|
| - // from consideration.
|
| -
|
| - // Trivially true.
|
| - if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
|
| - _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
|
| - return true;
|
| - }
|
| -
|
| - // Trivially false.
|
| - if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
|
| - _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
|
| - return false;
|
| - }
|
| -
|
| - // S <: T where S is a type variable
|
| - // T is not dynamic or object (handled above)
|
| - // S != T (handled above)
|
| - // So only true if bound of S is S' and
|
| - // S' <: T
|
| - if (t1 is TypeParameterType) {
|
| - DartType bound = t1.element.bound;
|
| - if (bound == null) return false;
|
| - return guardedSubtype(bound, t2, visited);
|
| - }
|
| -
|
| - if (t2 is TypeParameterType) {
|
| - return false;
|
| - }
|
| -
|
| - if (t1.isVoid || t2.isVoid) {
|
| - return false;
|
| - }
|
| -
|
| - // We've eliminated void, dynamic, bottom, and type parameters. The only
|
| - // cases are the combinations of interface type and function type.
|
| -
|
| - // A function type can only subtype an interface type if
|
| - // the interface type is Function
|
| - if (t1 is FunctionType && t2 is InterfaceType) {
|
| - return t2.isDartCoreFunction;
|
| - }
|
| -
|
| - // An interface type can only subtype a function type if
|
| - // the interface type declares a call method with a type
|
| - // which is a super type of the function type.
|
| - if (t1 is InterfaceType && t2 is FunctionType) {
|
| - var callType = _getCallMethodType(t1);
|
| - return (callType != null) && _isFunctionSubtypeOf(callType, t2);
|
| - }
|
| -
|
| - // Two interface types
|
| - if (t1 is InterfaceType && t2 is InterfaceType) {
|
| - return _isInterfaceSubtypeOf(t1, t2, visited);
|
| - }
|
| -
|
| - return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
|
| - }
|
| -
|
| - // TODO(leafp): Document the rules in play here
|
| - bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
|
| - return (t.isDynamic && !dynamicIsBottom) || t.isObject;
|
| - }
|
| -}
|
| -
|
| -/**
|
| * Instances of this class manage the knowledge of what the set of subtypes are for a given type.
|
| */
|
| class SubtypeManager {
|
| @@ -15332,139 +15029,6 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| }
|
|
|
| /**
|
| - * The interface `TypeSystem` defines the behavior of an object representing
|
| - * the type system. This provides a common location to put methods that act on
|
| - * types but may need access to more global data structures, and it paves the
|
| - * way for a possible future where we may wish to make the type system
|
| - * pluggable.
|
| - */
|
| -abstract class TypeSystem {
|
| - /**
|
| - * Compute the least upper bound of two types.
|
| - */
|
| - DartType getLeastUpperBound(
|
| - TypeProvider typeProvider, DartType type1, DartType type2);
|
| -
|
| - /**
|
| - * Return `true` if the [leftType] is assignable to the [rightType] (that is,
|
| - * if leftType <==> rightType).
|
| - */
|
| - bool isAssignableTo(DartType leftType, DartType rightType);
|
| -
|
| - /**
|
| - * Return `true` if the [leftType] is a subtype of the [rightType] (that is,
|
| - * if leftType <: rightType).
|
| - */
|
| - bool isSubtypeOf(DartType leftType, DartType rightType);
|
| -
|
| - /**
|
| - * Create either a strong mode or regular type system based on context.
|
| - */
|
| - static TypeSystem create(AnalysisContext context) {
|
| - return (context.analysisOptions.strongMode)
|
| - ? new StrongTypeSystemImpl()
|
| - : new TypeSystemImpl();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Implementation of [TypeSystem] using the rules in the Dart specification.
|
| - */
|
| -class TypeSystemImpl implements TypeSystem {
|
| - TypeSystemImpl();
|
| -
|
| - @override
|
| - DartType getLeastUpperBound(
|
| - TypeProvider typeProvider, DartType type1, DartType type2) {
|
| - // The least upper bound relation is reflexive.
|
| - if (identical(type1, type2)) {
|
| - return type1;
|
| - }
|
| - // The least upper bound of dynamic and any type T is dynamic.
|
| - if (type1.isDynamic) {
|
| - return type1;
|
| - }
|
| - if (type2.isDynamic) {
|
| - return type2;
|
| - }
|
| - // The least upper bound of void and any type T != dynamic is void.
|
| - if (type1.isVoid) {
|
| - return type1;
|
| - }
|
| - if (type2.isVoid) {
|
| - return type2;
|
| - }
|
| - // The least upper bound of bottom and any type T is T.
|
| - if (type1.isBottom) {
|
| - return type2;
|
| - }
|
| - if (type2.isBottom) {
|
| - return type1;
|
| - }
|
| - // Let U be a type variable with upper bound B. The least upper bound of U
|
| - // and a type T is the least upper bound of B and T.
|
| - while (type1 is TypeParameterType) {
|
| - // TODO(paulberry): is this correct in the complex of F-bounded
|
| - // polymorphism?
|
| - DartType bound = (type1 as TypeParameterType).element.bound;
|
| - if (bound == null) {
|
| - bound = typeProvider.objectType;
|
| - }
|
| - type1 = bound;
|
| - }
|
| - while (type2 is TypeParameterType) {
|
| - // TODO(paulberry): is this correct in the context of F-bounded
|
| - // polymorphism?
|
| - DartType bound = (type2 as TypeParameterType).element.bound;
|
| - if (bound == null) {
|
| - bound = typeProvider.objectType;
|
| - }
|
| - type2 = bound;
|
| - }
|
| - // The least upper bound of a function type and an interface type T is the
|
| - // least upper bound of Function and T.
|
| - if (type1 is FunctionType && type2 is InterfaceType) {
|
| - type1 = typeProvider.functionType;
|
| - }
|
| - if (type2 is FunctionType && type1 is InterfaceType) {
|
| - type2 = typeProvider.functionType;
|
| - }
|
| -
|
| - // At this point type1 and type2 should both either be interface types or
|
| - // function types.
|
| - if (type1 is InterfaceType && type2 is InterfaceType) {
|
| - InterfaceType result =
|
| - InterfaceTypeImpl.computeLeastUpperBound(type1, type2);
|
| - if (result == null) {
|
| - return typeProvider.dynamicType;
|
| - }
|
| - return result;
|
| - } else if (type1 is FunctionType && type2 is FunctionType) {
|
| - FunctionType result =
|
| - FunctionTypeImpl.computeLeastUpperBound(type1, type2);
|
| - if (result == null) {
|
| - return typeProvider.functionType;
|
| - }
|
| - return result;
|
| - } else {
|
| - // Should never happen. As a defensive measure, return the dynamic type.
|
| - assert(false);
|
| - return typeProvider.dynamicType;
|
| - }
|
| - }
|
| -
|
| - @override
|
| - bool isAssignableTo(DartType leftType, DartType rightType) {
|
| - return leftType.isAssignableTo(rightType);
|
| - }
|
| -
|
| - @override
|
| - bool isSubtypeOf(DartType leftType, DartType rightType) {
|
| - return leftType.isSubtypeOf(rightType);
|
| - }
|
| -}
|
| -
|
| -/**
|
| * Instances of the class [UnusedLocalElementsVerifier] traverse an element
|
| * structure looking for cases of [HintCode.UNUSED_ELEMENT],
|
| * [HintCode.UNUSED_FIELD], [HintCode.UNUSED_LOCAL_VARIABLE], etc.
|
|
|