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

Unified Diff: lib/type_algebra.dart

Issue 2439043002: Introduce Substitution class and Supertype class. (Closed)
Patch Set: Created 4 years, 2 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 | « lib/transformations/treeshaker.dart ('k') | lib/type_propagation/builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/type_algebra.dart
diff --git a/lib/type_algebra.dart b/lib/type_algebra.dart
index d8051302eeb959166484405a94e6b437bce8aa33..e93d870dc047dbab6aec93789c3467d468fba6d4 100644
--- a/lib/type_algebra.dart
+++ b/lib/type_algebra.dart
@@ -4,7 +4,6 @@
library kernel.type_algebra;
import 'ast.dart';
-import 'type_algebra.dart' as toplevel;
/// Returns a type where all occurrences of the given type parameters have been
/// replaced with the corresponding types.
@@ -17,72 +16,20 @@ import 'type_algebra.dart' as toplevel;
/// to efficiently check if a distinct type was created.
DartType substitute(DartType type, Map<TypeParameter, DartType> substitution) {
if (substitution.isEmpty) return type;
- return new _TypeSubstitutor(substitution, substitution).visit(type);
+ return Substitution.fromMap(substitution).substituteType(type);
}
/// Returns a mapping from the type parameters declared on the class of [type]
/// to the actual type arguments provided in [type].
///
/// This can be passed as argument to [substitute].
-Map<TypeParameter, DartType> getSubstitutionMap(InterfaceType type) {
+Map<TypeParameter, DartType> getSubstitutionMap(Supertype type) {
return type.typeArguments.isEmpty
? const <TypeParameter, DartType>{}
: new Map<TypeParameter, DartType>.fromIterables(
type.classNode.typeParameters, type.typeArguments);
}
-/// Like [substitute], but the substitution map is given as a list of keys
-/// and a list of values.
-DartType substitutePairwise(DartType type, List<TypeParameter> typeParameters,
- List<DartType> typeArguments) {
- if (typeParameters.isEmpty) return type;
- // TODO: Investigate if it is more efficient to implement substitution based
- // on parallel pairwise lists instead of Maps.
- return substitute(
- type,
- new Map<TypeParameter, DartType>.fromIterables(
- typeParameters, typeArguments));
-}
-
-/// Returns [type] where the type parameters declared on the class of [thisType]
-/// have been substituted with the type arguments provided in [thisType].
-///
-/// For example, if [thisType] is `Iterable<String>`, this will substitute
-/// `Iterable::E` with `String` in [type].
-///
-/// If `thisType` is null, nothing is substituted.
-DartType substituteThisType(DartType type, InterfaceType thisType) {
- if (thisType == null) return type;
- return substitutePairwise(
- type, thisType.classNode.typeParameters, thisType.typeArguments);
-}
-
-/// Returns a type where all occurrences of the given type parameters have been
-/// replaced with the corresponding upper or lower bound, depending on the
-/// variance of the context where it occurs.
-///
-/// For example the type `(T) => T` with the bounds `bottom <: T <: num`
-/// becomes `(bottom) => num` (in this example, `num` is the upper bound,
-/// and `bottom` is the lower bound).
-///
-/// This is a way to obtain an upper bound for a type while eliminating all
-/// references to certain type variables.
-///
-/// This will copy only the subterms of [type] that contain substituted
-/// variables; all other [DartType] objects will be reused.
-///
-/// In particular, if no variables were substituted, this is guaranteed to
-/// return the [type] instance (not a copy), so the caller may use [identical]
-/// to efficiently check if a distinct type was created.
-DartType substituteBounds(
- DartType type,
- Map<TypeParameter, DartType> upperBounds,
- Map<TypeParameter, DartType> lowerBounds) {
- assert(upperBounds.length == lowerBounds.length);
- if (upperBounds.isEmpty) return type;
- return new _TypeSubstitutor(upperBounds, lowerBounds).visit(type);
-}
-
/// Like [substitute], except when a type in the [substitution] map references
/// another substituted type variable, the mapping for that type is recursively
/// inserted.
@@ -146,34 +93,159 @@ FreshTypeParameters getFreshTypeParameters(List<TypeParameter> typeParameters) {
var freshParameters = new List<TypeParameter>.generate(
typeParameters.length, (i) => new TypeParameter(typeParameters[i].name),
growable: true);
- var substitution = <TypeParameter, DartType>{};
+ var map = <TypeParameter, DartType>{};
for (int i = 0; i < typeParameters.length; ++i) {
- substitution[typeParameters[i]] = new TypeParameterType(freshParameters[i]);
- freshParameters[i].bound =
- substitute(typeParameters[i].bound, substitution);
+ map[typeParameters[i]] = new TypeParameterType(freshParameters[i]);
+ freshParameters[i].bound = substitute(typeParameters[i].bound, map);
}
- return new FreshTypeParameters(freshParameters, substitution);
+ return new FreshTypeParameters(freshParameters, Substitution.fromMap(map));
}
class FreshTypeParameters {
final List<TypeParameter> freshTypeParameters;
- final Map<TypeParameter, DartType> substitution;
+ final Substitution substitution;
FreshTypeParameters(this.freshTypeParameters, this.substitution);
- DartType substitute(DartType type) => toplevel.substitute(type, substitution);
+ DartType substitute(DartType type) => substitution.substituteType(type);
+
+ Supertype substituteSuper(Supertype type) {
+ return substitution.substituteSupertype(type);
+ }
}
// ------------------------------------------------------------------------
// IMPLEMENTATION
// ------------------------------------------------------------------------
-class _TypeSubstitutor extends DartTypeVisitor<DartType> {
- final Map<TypeParameter, DartType> upperBounds;
- final Map<TypeParameter, DartType> lowerBounds;
+abstract class Substitution {
+ /// Substitutes each parameter to the type it maps to in [map].
+ static Substitution fromMap(Map<TypeParameter, DartType> map) {
+ if (map.isEmpty) return _NullSubstitution.instance;
+ return new _MapSubstitution(map, map);
+ }
+
+ /// Substitutes all occurrences of the given type parameters with the
+ /// corresponding upper or lower bound, depending on the variance of the
+ /// context where it occurs.
+ ///
+ /// For example the type `(T) => T` with the bounds `bottom <: T <: num`
+ /// becomes `(bottom) => num` (in this example, `num` is the upper bound,
+ /// and `bottom` is the lower bound).
+ ///
+ /// This is a way to obtain an upper bound for a type while eliminating all
+ /// references to certain type variables.
+ static Substitution fromUpperAndLowerBounds(
+ Map<TypeParameter, DartType> upper, Map<TypeParameter, DartType> lower) {
+ if (upper.isEmpty && lower.isEmpty) return _NullSubstitution.instance;
+ return new _MapSubstitution(upper, lower);
+ }
+
+ /// Substitutes the type parameters on the class of [supertype] with the
+ /// type arguments provided in [supertype].
+ static Substitution fromSupertype(Supertype supertype) {
+ if (supertype.typeArguments.isEmpty) return _NullSubstitution.instance;
+ return fromMap(new Map<TypeParameter, DartType>.fromIterables(
+ supertype.classNode.typeParameters, supertype.typeArguments));
+ }
+
+ /// Substitutes the type parameters on the class of [type] with the
+ /// type arguments provided in [type].
+ static Substitution fromInterfaceType(InterfaceType type) {
+ if (type.typeArguments.isEmpty) return _NullSubstitution.instance;
+ return fromMap(new Map<TypeParameter, DartType>.fromIterables(
+ type.classNode.typeParameters, type.typeArguments));
+ }
+
+ /// Substitutes the Nth parameter in [parameters] with the Nth type in
+ /// [types].
+ static Substitution fromPairs(
+ List<TypeParameter> parameters, List<DartType> types) {
+ // TODO(asgerf): Investigate if it is more efficient to implement
+ // substitution based on parallel pairwise lists instead of Maps.
+ assert(parameters.length == types.length);
+ if (parameters.isEmpty) return _NullSubstitution.instance;
+ return fromMap(
+ new Map<TypeParameter, DartType>.fromIterables(parameters, types));
+ }
+
+ DartType getSubstitute(TypeParameter parameter, bool upperBound);
+
+ DartType substituteType(DartType node) {
+ return new _TopSubstitutor(this).visit(node);
+ }
+
+ Supertype substituteSupertype(Supertype node) {
+ return new _TopSubstitutor(this).visitSupertype(node);
+ }
+}
+
+class _NullSubstitution extends Substitution {
+ static final _NullSubstitution instance = new _NullSubstitution();
+
+ DartType getSubstitute(TypeParameter parameter, bool upperBound) {
+ return new TypeParameterType(parameter);
+ }
+
+ @override
+ DartType substituteType(DartType node) => node;
+
+ @override
+ Supertype substituteSupertype(Supertype node) => node;
+}
+
+class _MapSubstitution extends Substitution {
+ final Map<TypeParameter, DartType> upper;
+ final Map<TypeParameter, DartType> lower;
+
+ _MapSubstitution(this.upper, this.lower);
+
+ DartType getSubstitute(TypeParameter parameter, bool upperBound) {
+ return upperBound ? upper[parameter] : lower[parameter];
+ }
+}
+
+class _TopSubstitutor extends _TypeSubstitutor {
+ final Substitution substitution;
+
+ _TopSubstitutor(this.substitution) : super(null);
+
+ DartType lookup(TypeParameter parameter, bool upperBound) {
+ return substitution.getSubstitute(parameter, upperBound);
+ }
+
+ TypeParameter freshTypeParameter(TypeParameter node) {
+ throw 'Create a fresh environment first';
+ }
+}
+
+class _InnerTypeSubstitutor extends _TypeSubstitutor {
+ final Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
+
+ _InnerTypeSubstitutor(_TypeSubstitutor outer) : super(outer);
+
+ DartType lookup(TypeParameter parameter, bool upperBound) {
+ return substitution[parameter];
+ }
+
+ TypeParameter freshTypeParameter(TypeParameter node) {
+ var fresh = new TypeParameter(node.name);
+ substitution[node] = new TypeParameterType(fresh);
+ fresh.bound = visit(node.bound);
+ return fresh;
+ }
+}
+
+abstract class _TypeSubstitutor extends DartTypeVisitor<DartType> {
final _TypeSubstitutor outer;
bool covariantContext = true;
+ _TypeSubstitutor(this.outer) {
+ covariantContext = outer == null ? true : outer.covariantContext;
+ }
+
+ DartType lookup(TypeParameter parameter, bool upperBound);
+
/// The number of times a variable from this environment has been used in
/// a substitution.
///
@@ -182,19 +254,22 @@ class _TypeSubstitutor extends DartTypeVisitor<DartType> {
/// check quickly if anything happened in a substitution.
int useCounter = 0;
- _TypeSubstitutor(this.upperBounds, this.lowerBounds, [this.outer]) {
- covariantContext = outer == null ? true : outer.covariantContext;
- }
-
- _TypeSubstitutor newInnerEnvironment() {
- var map = <TypeParameter, DartType>{};
- return new _TypeSubstitutor(map, map, this);
+ _InnerTypeSubstitutor newInnerEnvironment() {
+ return new _InnerTypeSubstitutor(this);
}
void invertVariance() {
covariantContext = !covariantContext;
}
+ Supertype visitSupertype(Supertype node) {
+ if (node.typeArguments.isEmpty) return node;
+ int before = useCounter;
+ var typeArguments = node.typeArguments.map(visit).toList();
+ if (useCounter == before) return node;
+ return new Supertype(node.classNode, typeArguments);
+ }
+
DartType visit(DartType node) => node.accept(this);
DartType visitInvalidType(InvalidType node) => node;
@@ -215,15 +290,9 @@ class _TypeSubstitutor extends DartTypeVisitor<DartType> {
return parameters.map(freshTypeParameter).toList();
}
- TypeParameter freshTypeParameter(TypeParameter node) {
- var fresh = new TypeParameter(node.name);
- upperBounds[node] = new TypeParameterType(fresh);
- fresh.bound = visit(node.bound);
- return fresh;
- }
+ TypeParameter freshTypeParameter(TypeParameter node);
DartType visitFunctionType(FunctionType node) {
- assert(!node.typeParameters.any(upperBounds.containsKey));
// This is a bit tricky because we have to generate fresh type parameters
// in order to change the bounds. At the same time, if the function type
// was unaltered, we have to return the [node] object (not a copy!).
@@ -267,9 +336,7 @@ class _TypeSubstitutor extends DartTypeVisitor<DartType> {
DartType getSubstitute(TypeParameter variable) {
var environment = this;
while (environment != null) {
- var replacement = covariantContext
- ? environment.upperBounds[variable]
- : environment.lowerBounds[variable];
+ var replacement = environment.lookup(variable, covariantContext);
if (replacement != null) {
bumpCountersUntil(environment);
return replacement;
@@ -284,13 +351,15 @@ class _TypeSubstitutor extends DartTypeVisitor<DartType> {
}
}
-class _DeepTypeSubstitutor extends _TypeSubstitutor {
+class _DeepTypeSubstitutor extends _InnerTypeSubstitutor {
int depth = 0;
bool isInfinite = false;
_DeepTypeSubstitutor(Map<TypeParameter, DartType> substitution,
[_DeepTypeSubstitutor outer])
- : super(substitution, substitution, outer);
+ : super(outer) {
+ this.substitution.addAll(substitution);
+ }
@override
_TypeSubstitutor newInnerEnvironment() {
@@ -303,14 +372,14 @@ class _DeepTypeSubstitutor extends _TypeSubstitutor {
if (replacement == null) return node;
if (isInfinite) return replacement;
++depth;
- if (depth > upperBounds.length) {
+ if (depth > substitution.length) {
isInfinite = true;
--depth;
return replacement;
} else {
replacement = visit(replacement);
// Update type to the fully fleshed-out type.
- upperBounds[node.parameter] = replacement;
+ substitution[node.parameter] = replacement;
--depth;
return replacement;
}
« no previous file with comments | « lib/transformations/treeshaker.dart ('k') | lib/type_propagation/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698