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

Unified Diff: pkg/compiler/lib/src/elements/types.dart

Issue 2829683007: Extract DartTypeVisitor and subclasses from resolution_types. (Closed)
Patch Set: Created 3 years, 8 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 | « pkg/compiler/lib/src/elements/resolution_types.dart ('k') | pkg/compiler/lib/src/js_backend/namer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/elements/types.dart
diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart
index 946a03590ed907810a83c7cab589a6e6c23d143a..f8a4a4e899b65e03b60981dd1aea3d218742c431 100644
--- a/pkg/compiler/lib/src/elements/types.dart
+++ b/pkg/compiler/lib/src/elements/types.dart
@@ -2,8 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import 'entities.dart';
+import '../common_elements.dart';
import '../util/util.dart' show equalElements;
+import 'entities.dart';
/// Hierarchy to describe types in Dart.
///
@@ -77,6 +78,9 @@ abstract class DartType {
///
/// Invariant: There must be the same number of [arguments] and [parameters].
DartType subst(List<DartType> arguments, List<DartType> parameters);
+
+ /// Calls the visit method on [visitor] corresponding to this type.
+ R accept<R, A>(DartTypeVisitor<R, A> visitor, A argument);
}
class InterfaceType extends DartType {
@@ -111,6 +115,10 @@ class InterfaceType extends DartType {
return this;
}
+ @override
+ R accept<R, A>(DartTypeVisitor visitor, A argument) =>
+ visitor.visitInterfaceType(this, argument);
+
int get hashCode {
int hash = element.hashCode;
for (DartType argument in typeArguments) {
@@ -172,6 +180,10 @@ class TypeVariableType extends DartType {
return this;
}
+ @override
+ R accept<R, A>(DartTypeVisitor visitor, A argument) =>
+ visitor.visitTypeVariableType(this, argument);
+
int get hashCode => 17 * element.hashCode;
bool operator ==(other) {
@@ -192,6 +204,10 @@ class VoidType extends DartType {
return this;
}
+ @override
+ R accept<R, A>(DartTypeVisitor visitor, A argument) =>
+ visitor.visitVoidType(this, argument);
+
int get hashCode => 6007;
String toString() => 'void';
@@ -211,6 +227,10 @@ class DynamicType extends DartType {
return this;
}
+ @override
+ R accept<R, A>(DartTypeVisitor visitor, A argument) =>
+ visitor.visitDynamicType(this, argument);
+
int get hashCode => 91;
String toString() => 'dynamic';
@@ -279,6 +299,10 @@ class FunctionType extends DartType {
return this;
}
+ @override
+ R accept<R, A>(DartTypeVisitor visitor, A argument) =>
+ visitor.visitFunctionType(this, argument);
+
int get hashCode {
int hash = 3 * returnType.hashCode;
for (DartType parameter in parameterTypes) {
@@ -373,3 +397,327 @@ List<DartType> _substTypes(
// Use the new List only if necessary.
return changed ? result : types;
}
+
+abstract class DartTypeVisitor<R, A> {
+ const DartTypeVisitor();
+
+ R visit(DartType type, A argument) => type.accept(this, argument);
+
+ R visitVoidType(VoidType type, A argument) => null;
+
+ R visitTypeVariableType(TypeVariableType type, A argument) => null;
+
+ R visitFunctionType(FunctionType type, A argument) => null;
+
+ R visitInterfaceType(InterfaceType type, A argument) => null;
+
+ R visitDynamicType(DynamicType type, A argument) => null;
+}
+
+abstract class BaseDartTypeVisitor<R, A> extends DartTypeVisitor<R, A> {
+ const BaseDartTypeVisitor();
+
+ R visitType(DartType type, A argument);
+
+ @override
+ R visitVoidType(VoidType type, A argument) => visitType(type, argument);
+
+ @override
+ R visitTypeVariableType(TypeVariableType type, A argument) =>
+ visitType(type, argument);
+
+ @override
+ R visitFunctionType(FunctionType type, A argument) =>
+ visitType(type, argument);
+
+ @override
+ R visitInterfaceType(InterfaceType type, A argument) =>
+ visitType(type, argument);
+
+ @override
+ R visitDynamicType(DynamicType type, A argument) => visitType(type, argument);
+}
+
+/// Abstract visitor for determining relations between types.
+abstract class AbstractTypeRelation
+ extends BaseDartTypeVisitor<bool, DartType> {
+ CommonElements get commonElements;
+
+ /// Ensures that the super hierarchy of [type] is computed.
+ void ensureResolved(InterfaceType type) {}
+
+ /// Returns the unaliased version of [type].
+ DartType getUnaliased(DartType type) => type.unaliased;
+
+ /// Returns [type] as an instance of [cls], or `null` if [type] is not subtype
+ /// if [cls].
+ InterfaceType asInstanceOf(InterfaceType type, ClassEntity cls);
+
+ /// Returns the type of the `call` method on [type], or `null` if the class
+ /// of [type] does not have a `call` method.
+ FunctionType getCallType(InterfaceType type);
+
+ /// Returns the declared bound of [element].
+ DartType getTypeVariableBound(TypeVariableEntity element);
+
+ bool visitType(DartType t, DartType s) {
+ throw 'internal error: unknown type ${t}';
+ }
+
+ bool visitVoidType(VoidType t, DartType s) {
+ assert(s is! VoidType);
+ return false;
+ }
+
+ bool invalidTypeArguments(DartType t, DartType s);
+
+ bool invalidFunctionReturnTypes(DartType t, DartType s);
+
+ bool invalidFunctionParameterTypes(DartType t, DartType s);
+
+ bool invalidTypeVariableBounds(DartType bound, DartType s);
+
+ bool invalidCallableType(DartType callType, DartType s);
+
+ bool visitInterfaceType(InterfaceType t, DartType s) {
+ ensureResolved(t);
+
+ bool checkTypeArguments(InterfaceType instance, InterfaceType other) {
+ List<DartType> tTypeArgs = instance.typeArguments;
+ List<DartType> sTypeArgs = other.typeArguments;
+ assert(tTypeArgs.length == sTypeArgs.length);
+ for (int i = 0; i < tTypeArgs.length; i++) {
+ if (invalidTypeArguments(tTypeArgs[i], sTypeArgs[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ if (s is InterfaceType) {
+ InterfaceType instance = asInstanceOf(t, s.element);
+ if (instance != null && checkTypeArguments(instance, s)) {
+ return true;
+ }
+ }
+
+ FunctionType callType = getCallType(t);
+ if (s == commonElements.functionType && callType != null) {
+ return true;
+ } else if (s is FunctionType) {
+ return callType != null && !invalidCallableType(callType, s);
+ }
+
+ return false;
+ }
+
+ bool visitFunctionType(FunctionType t, DartType s) {
+ if (s == commonElements.functionType) {
+ return true;
+ }
+ if (s is! FunctionType) return false;
+ FunctionType tf = t;
+ FunctionType sf = s;
+ if (invalidFunctionReturnTypes(tf.returnType, sf.returnType)) {
+ return false;
+ }
+
+ // TODO(johnniwinther): Rewrite the function subtyping to be more readable
+ // but still as efficient.
+
+ // For the comments we use the following abbreviations:
+ // x.p : parameterTypes on [:x:],
+ // x.o : optionalParameterTypes on [:x:], and
+ // len(xs) : length of list [:xs:].
+
+ Iterator<DartType> tps = tf.parameterTypes.iterator;
+ Iterator<DartType> sps = sf.parameterTypes.iterator;
+ bool sNotEmpty = sps.moveNext();
+ bool tNotEmpty = tps.moveNext();
+ tNext() => (tNotEmpty = tps.moveNext());
+ sNext() => (sNotEmpty = sps.moveNext());
+
+ bool incompatibleParameters() {
+ while (tNotEmpty && sNotEmpty) {
+ if (invalidFunctionParameterTypes(tps.current, sps.current)) {
+ return true;
+ }
+ tNext();
+ sNext();
+ }
+ return false;
+ }
+
+ if (incompatibleParameters()) return false;
+ if (tNotEmpty) {
+ // We must have [: len(t.p) <= len(s.p) :].
+ return false;
+ }
+ if (!sf.namedParameters.isEmpty) {
+ // We must have [: len(t.p) == len(s.p) :].
+ if (sNotEmpty) {
+ return false;
+ }
+ // Since named parameters are globally ordered we can determine the
+ // subset relation with a linear search for [:sf.namedParameters:]
+ // within [:tf.namedParameters:].
+ List<String> tNames = tf.namedParameters;
+ List<DartType> tTypes = tf.namedParameterTypes;
+ List<String> sNames = sf.namedParameters;
+ List<DartType> sTypes = sf.namedParameterTypes;
+ int tIndex = 0;
+ int sIndex = 0;
+ while (tIndex < tNames.length && sIndex < sNames.length) {
+ if (tNames[tIndex] == sNames[sIndex]) {
+ if (invalidFunctionParameterTypes(tTypes[tIndex], sTypes[sIndex])) {
+ return false;
+ }
+ sIndex++;
+ }
+ tIndex++;
+ }
+ if (sIndex < sNames.length) {
+ // We didn't find all names.
+ return false;
+ }
+ } else {
+ // Check the remaining [: s.p :] against [: t.o :].
+ tps = tf.optionalParameterTypes.iterator;
+ tNext();
+ if (incompatibleParameters()) return false;
+ if (sNotEmpty) {
+ // We must have [: len(t.p) + len(t.o) >= len(s.p) :].
+ return false;
+ }
+ if (!sf.optionalParameterTypes.isEmpty) {
+ // Check the remaining [: s.o :] against the remaining [: t.o :].
+ sps = sf.optionalParameterTypes.iterator;
+ sNext();
+ if (incompatibleParameters()) return false;
+ if (sNotEmpty) {
+ // We didn't find enough parameters:
+ // We must have [: len(t.p) + len(t.o) <= len(s.p) + len(s.o) :].
+ return false;
+ }
+ } else {
+ if (sNotEmpty) {
+ // We must have [: len(t.p) + len(t.o) >= len(s.p) :].
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ bool visitTypeVariableType(TypeVariableType t, DartType s) {
+ // Identity check is handled in [isSubtype].
+ DartType bound = getTypeVariableBound(t.element);
+ if (bound.isTypeVariable) {
+ // The bound is potentially cyclic so we need to be extra careful.
+ Set<TypeVariableEntity> seenTypeVariables = new Set<TypeVariableEntity>();
+ seenTypeVariables.add(t.element);
+ while (bound.isTypeVariable) {
+ TypeVariableType typeVariable = bound;
+ if (bound == s) {
+ // [t] extends [s].
+ return true;
+ }
+ if (seenTypeVariables.contains(typeVariable.element)) {
+ // We have a cycle and have already checked all bounds in the cycle
+ // against [s] and can therefore conclude that [t] is not a subtype
+ // of [s].
+ return false;
+ }
+ seenTypeVariables.add(typeVariable.element);
+ bound = getTypeVariableBound(typeVariable.element);
+ }
+ }
+ if (invalidTypeVariableBounds(bound, s)) return false;
+ return true;
+ }
+}
+
+abstract class MoreSpecificVisitor extends AbstractTypeRelation {
+ bool isMoreSpecific(DartType t, DartType s) {
+ if (identical(t, s) || s.treatAsDynamic || t == commonElements.nullType) {
+ return true;
+ }
+ if (t.isVoid || s.isVoid) {
+ return false;
+ }
+ if (t.treatAsDynamic) {
+ return false;
+ }
+ if (s == commonElements.objectType) {
+ return true;
+ }
+ t = getUnaliased(t);
+ s = getUnaliased(s);
+
+ return t.accept(this, s);
+ }
+
+ bool invalidTypeArguments(DartType t, DartType s) {
+ return !isMoreSpecific(t, s);
+ }
+
+ bool invalidFunctionReturnTypes(DartType t, DartType s) {
+ if (s.treatAsDynamic && t.isVoid) return true;
+ return !s.isVoid && !isMoreSpecific(t, s);
+ }
+
+ bool invalidFunctionParameterTypes(DartType t, DartType s) {
+ return !isMoreSpecific(t, s);
+ }
+
+ bool invalidTypeVariableBounds(DartType bound, DartType s) {
+ return !isMoreSpecific(bound, s);
+ }
+
+ bool invalidCallableType(DartType callType, DartType s) {
+ return !isMoreSpecific(callType, s);
+ }
+}
+
+/// Type visitor that determines the subtype relation two types.
+abstract class SubtypeVisitor extends MoreSpecificVisitor {
+ bool isSubtype(DartType t, DartType s) {
+ return t.treatAsDynamic || isMoreSpecific(t, s);
+ }
+
+ bool isAssignable(DartType t, DartType s) {
+ return isSubtype(t, s) || isSubtype(s, t);
+ }
+
+ bool invalidTypeArguments(DartType t, DartType s) {
+ return !isSubtype(t, s);
+ }
+
+ bool invalidFunctionReturnTypes(DartType t, DartType s) {
+ return !s.isVoid && !isAssignable(t, s);
+ }
+
+ bool invalidFunctionParameterTypes(DartType t, DartType s) {
+ return !isAssignable(t, s);
+ }
+
+ bool invalidTypeVariableBounds(DartType bound, DartType s) {
+ return !isSubtype(bound, s);
+ }
+
+ bool invalidCallableType(DartType callType, DartType s) {
+ return !isSubtype(callType, s);
+ }
+}
+
+/// Type visitor that determines one type could a subtype of another given the
+/// right type variable substitution. The computation is approximate and returns
+/// `false` only if we are sure no such substitution exists.
+abstract class PotentialSubtypeVisitor extends SubtypeVisitor {
+ bool isSubtype(DartType t, DartType s) {
+ if (t is TypeVariableType || s is TypeVariableType) {
+ return true;
+ }
+ return super.isSubtype(t, s);
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/elements/resolution_types.dart ('k') | pkg/compiler/lib/src/js_backend/namer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698