@@ -83,6 +83,98 @@ sealed class TypeVariableBuilderBase extends TypeDeclarationBuilderImpl
83
83
84
84
void finish (SourceLibraryBuilder library, ClassBuilder object,
85
85
TypeBuilder dynamicType);
86
+
87
+ TypeBuilder ? _unaliasAndErase (TypeBuilder ? typeBuilder) {
88
+ if (typeBuilder is ! NamedTypeBuilder ) {
89
+ return typeBuilder;
90
+ } else {
91
+ TypeDeclarationBuilder ? declaration = typeBuilder.declaration;
92
+ if (declaration is TypeAliasBuilder ) {
93
+ // We pass empty lists as [unboundTypes] and [unboundTypeVariables]
94
+ // because new builders can be generated during unaliasing. We ignore
95
+ // the returned builders, however, because they will not be used in the
96
+ // output and are needed only for the checks.
97
+ //
98
+ // We also don't instantiate-to-bound raw types because it won't affect
99
+ // the dependency cycle analysis.
100
+ return _unaliasAndErase (declaration.unalias (typeBuilder.typeArguments,
101
+ unboundTypes: [], unboundTypeVariables: []));
102
+ } else if (declaration is ExtensionTypeDeclarationBuilder ) {
103
+ TypeBuilder ? representationType =
104
+ declaration.declaredRepresentationTypeBuilder;
105
+ if (representationType == null ) {
106
+ return null ;
107
+ } else {
108
+ List <NominalVariableBuilder >? typeParameters =
109
+ declaration.typeParameters;
110
+ List <TypeBuilder >? typeArguments = typeBuilder.typeArguments;
111
+ if (typeParameters != null && typeArguments != null ) {
112
+ representationType = representationType.subst (
113
+ new Map <NominalVariableBuilder , TypeBuilder >.fromIterables (
114
+ typeParameters, typeArguments));
115
+ }
116
+ return _unaliasAndErase (representationType);
117
+ }
118
+ } else {
119
+ return typeBuilder;
120
+ }
121
+ }
122
+ }
123
+
124
+ TypeVariableCyclicDependency ? findCyclicDependency (
125
+ {Map <TypeVariableBuilderBase , TypeVariableTraversalState >?
126
+ typeVariablesTraversalState,
127
+ Map <TypeVariableBuilderBase , TypeVariableBuilderBase >? cycleElements}) {
128
+ typeVariablesTraversalState ?? = {};
129
+ cycleElements ?? = {};
130
+
131
+ switch (typeVariablesTraversalState[this ] ?? =
132
+ TypeVariableTraversalState .unvisited) {
133
+ case TypeVariableTraversalState .visited:
134
+ return null ;
135
+ case TypeVariableTraversalState .active:
136
+ typeVariablesTraversalState[this ] = TypeVariableTraversalState .visited;
137
+ List <TypeVariableBuilderBase >? viaTypeVariables;
138
+ TypeVariableBuilderBase ? nextViaTypeVariable = cycleElements[this ];
139
+ while (nextViaTypeVariable != null && nextViaTypeVariable != this ) {
140
+ (viaTypeVariables ?? = []).add (nextViaTypeVariable);
141
+ nextViaTypeVariable = cycleElements[nextViaTypeVariable];
142
+ }
143
+ return new TypeVariableCyclicDependency (this ,
144
+ viaTypeVariables: viaTypeVariables);
145
+ case TypeVariableTraversalState .unvisited:
146
+ typeVariablesTraversalState[this ] = TypeVariableTraversalState .active;
147
+ TypeBuilder ? bound = this .bound;
148
+ if (bound is NamedTypeBuilder ) {
149
+ TypeBuilder ? unaliasedAndErasedBound = _unaliasAndErase (bound);
150
+ TypeDeclarationBuilder ? unaliasedAndErasedBoundDeclaration =
151
+ unaliasedAndErasedBound? .declaration;
152
+ TypeVariableBuilderBase ? nextVariable;
153
+ if (unaliasedAndErasedBoundDeclaration is TypeVariableBuilderBase ) {
154
+ nextVariable = unaliasedAndErasedBoundDeclaration;
155
+ }
156
+
157
+ if (nextVariable != null ) {
158
+ cycleElements[this ] = nextVariable;
159
+ TypeVariableCyclicDependency ? result =
160
+ nextVariable.findCyclicDependency (
161
+ typeVariablesTraversalState: typeVariablesTraversalState,
162
+ cycleElements: cycleElements);
163
+ typeVariablesTraversalState[this ] =
164
+ TypeVariableTraversalState .visited;
165
+ return result;
166
+ } else {
167
+ typeVariablesTraversalState[this ] =
168
+ TypeVariableTraversalState .visited;
169
+ return null ;
170
+ }
171
+ } else {
172
+ typeVariablesTraversalState[this ] =
173
+ TypeVariableTraversalState .visited;
174
+ return null ;
175
+ }
176
+ }
177
+ }
86
178
}
87
179
88
180
class NominalVariableBuilder extends TypeVariableBuilderBase {
@@ -310,21 +402,17 @@ class NominalVariableBuilder extends TypeVariableBuilderBase {
310
402
}
311
403
}
312
404
313
- List < /* TypeVariableBuilder | FunctionTypeTypeVariableBuilder */ Object >
314
- sortAllTypeVariablesTopologically (
315
- Iterable < /* TypeVariableBuilder | FunctionTypeTypeVariableBuilder */
316
- Object >
317
- typeVariables) {
405
+ List <TypeVariableBuilderBase > sortAllTypeVariablesTopologically (
406
+ Iterable <TypeVariableBuilderBase > typeVariables) {
318
407
assert (typeVariables.every ((typeVariable) =>
319
408
typeVariable is NominalVariableBuilder ||
320
409
typeVariable is StructuralVariableBuilder ));
321
410
322
- Set < /* TypeVariableBuilder | FunctionTypeTypeVariableBuilder */ Object >
323
- unhandled = new Set <Object >.identity ()..addAll (typeVariables);
324
- List < /* TypeVariableBuilder | FunctionTypeTypeVariableBuilder */ Object >
325
- result = < Object > [];
411
+ Set <TypeVariableBuilderBase > unhandled =
412
+ new Set <TypeVariableBuilderBase >.identity ()..addAll (typeVariables);
413
+ List <TypeVariableBuilderBase > result = < TypeVariableBuilderBase > [];
326
414
while (unhandled.isNotEmpty) {
327
- Object rootVariable = unhandled.first;
415
+ TypeVariableBuilderBase rootVariable = unhandled.first;
328
416
unhandled.remove (rootVariable);
329
417
330
418
TypeBuilder ? rootVariableBound;
@@ -684,3 +772,47 @@ class FreshStructuralVariableBuildersFromNominalVariableBuilders {
684
772
FreshStructuralVariableBuildersFromNominalVariableBuilders (
685
773
this .freshStructuralVariableBuilders, this .substitutionMap);
686
774
}
775
+
776
+ /// This enum is used internally for dependency analysis of type variables.
777
+ enum TypeVariableTraversalState {
778
+ /// An [unvisited] type variable isn't yet visited by the traversal algorithm.
779
+ unvisited,
780
+
781
+ /// An [active] type variable is traversed, but not fully processed.
782
+ active,
783
+
784
+ /// A [visited] type variable is fully processed.
785
+ visited;
786
+ }
787
+
788
+ /// Represents a cyclic dependency of a type variable on itself.
789
+ ///
790
+ /// An examples of such dependencies are X in the following cases.
791
+ ///
792
+ /// typedef F<Y> = Y;
793
+ /// extension type E<Y>(Y it) {}
794
+ ///
795
+ /// class A<X extends X> {} // Error.
796
+ /// class B<X extends Y, Y extends X> {} // Error.
797
+ /// class C<X extends F<Y>, Y extends X> {} // Error.
798
+ /// class D<X extends E<Y>, Y extends X> {} // Error.
799
+ class TypeVariableCyclicDependency {
800
+ /// Type variable that's the bound of itself.
801
+ final TypeVariableBuilderBase typeVariableBoundOfItself;
802
+
803
+ /// The elements in a non-trivial self-dependency cycle.
804
+ ///
805
+ /// The loop is considered non-trivial if it includes more than one type
806
+ /// variable.
807
+ final List <TypeVariableBuilderBase >? viaTypeVariables;
808
+
809
+ TypeVariableCyclicDependency (this .typeVariableBoundOfItself,
810
+ {this .viaTypeVariables});
811
+
812
+ @override
813
+ String toString () {
814
+ return "TypeVariableCyclicDependency("
815
+ "typeVariableBoundOfItself=${typeVariableBoundOfItself }, "
816
+ "viaTypeVariable=${viaTypeVariables })" ;
817
+ }
818
+ }
0 commit comments