@@ -12,7 +12,30 @@ import '../elements/types.dart';
1212/// A type environment maps type parameter variables to type values. The type
1313/// variables are mostly elided in the runtime representation, replaced by
1414/// indexes into the reified environment.
15- abstract class TypeEnvironmentStructure {}
15+ abstract class TypeEnvironmentStructure {
16+ /// Structural equality on [TypeEnvironmentStructure] .
17+ static bool same (TypeEnvironmentStructure a, TypeEnvironmentStructure b) {
18+ if (a is SingletonTypeEnvironmentStructure ) {
19+ if (b is SingletonTypeEnvironmentStructure ) {
20+ return a.variable == b.variable;
21+ }
22+ return false ;
23+ }
24+ return _sameFullStructure (a, b);
25+ }
26+
27+ static bool _sameFullStructure (
28+ FullTypeEnvironmentStructure a, FullTypeEnvironmentStructure b) {
29+ if (a.classType != b.classType) return false ;
30+ List <TypeVariableType > aBindings = a.bindings;
31+ List <TypeVariableType > bBindings = b.bindings;
32+ if (aBindings.length != bBindings.length) return false ;
33+ for (int i = 0 ; i < aBindings.length; i++ ) {
34+ if (aBindings[i] != bBindings[i]) return false ;
35+ }
36+ return true ;
37+ }
38+ }
1639
1740/// A singleton type environment maps a binds a single value.
1841class SingletonTypeEnvironmentStructure extends TypeEnvironmentStructure {
@@ -38,14 +61,37 @@ class FullTypeEnvironmentStructure extends TypeEnvironmentStructure {
3861
3962/// A TypeRecipe is evaluated against a type environment to produce either a
4063/// type, or another type environment.
41- abstract class TypeRecipe {}
64+ abstract class TypeRecipe {
65+ /// Returns `true` is [recipeB] evaluated in an environment described by
66+ /// [structureB] gives the same type as [recipeA] evaluated in environment
67+ /// described by [structureA] .
68+ static bool yieldsSameType (
69+ TypeRecipe recipeA,
70+ TypeEnvironmentStructure structureA,
71+ TypeRecipe recipeB,
72+ TypeEnvironmentStructure structureB) {
73+ if (recipeA == recipeB &&
74+ TypeEnvironmentStructure .same (structureA, structureB)) {
75+ return true ;
76+ }
77+
78+ // TODO(sra): Type recipes that are different but equal modulo naming also
79+ // yield the same type, e.g. `List<X> @X` and `List<Y> @Y`.
80+ return false ;
81+ }
82+ }
4283
4384/// A recipe that yields a reified type.
4485class TypeExpressionRecipe extends TypeRecipe {
4586 final DartType type;
4687
4788 TypeExpressionRecipe (this .type);
4889
90+ @override
91+ bool operator == (other) {
92+ return other is TypeExpressionRecipe && type == other.type;
93+ }
94+
4995 @override
5096 String toString () => 'TypeExpressionRecipe($type )' ;
5197}
@@ -60,6 +106,11 @@ class SingletonTypeEnvironmentRecipe extends TypeEnvironmentRecipe {
60106
61107 SingletonTypeEnvironmentRecipe (this .type);
62108
109+ @override
110+ bool operator == (other) {
111+ return other is SingletonTypeEnvironmentRecipe && type == other.type;
112+ }
113+
63114 @override
64115 String toString () => 'SingletonTypeEnvironmentRecipe($type )' ;
65116}
@@ -80,6 +131,22 @@ class FullTypeEnvironmentRecipe extends TypeEnvironmentRecipe {
80131
81132 FullTypeEnvironmentRecipe ({this .classType, this .types = const []});
82133
134+ @override
135+ bool operator == (other) {
136+ return other is FullTypeEnvironmentRecipe && _equal (this , other);
137+ }
138+
139+ static bool _equal (FullTypeEnvironmentRecipe a, FullTypeEnvironmentRecipe b) {
140+ if (a.classType != b.classType) return false ;
141+ List <DartType > aTypes = a.types;
142+ List <DartType > bTypes = b.types;
143+ if (aTypes.length != bTypes.length) return false ;
144+ for (int i = 0 ; i < aTypes.length; i++ ) {
145+ if (aTypes[i] != bTypes[i]) return false ;
146+ }
147+ return true ;
148+ }
149+
83150 @override
84151 String toString () => 'FullTypeEnvironmentRecipe($classType , $types )' ;
85152}
0 commit comments