@@ -164,14 +164,23 @@ class FunctionType extends Type
164164 ..excludeNamesUsedIn (other);
165165 var thisSubstitution = < TypeParameter , Type > {};
166166 var otherSubstitution = < TypeParameter , Type > {};
167+ var thisTypeFormalBounds = < Type > [];
168+ var otherTypeFormalBounds = < Type > [];
167169 for (var i = 0 ; i < typeFormals.length; i++ ) {
168170 var freshTypeParameterType =
169171 TypeParameterType (freshTypeParameterGenerator.generate ());
170172 thisSubstitution[typeFormals[i]] = freshTypeParameterType;
171173 otherSubstitution[other.typeFormals[i]] = freshTypeParameterType;
174+ thisTypeFormalBounds.add (typeFormals[i].bound);
175+ otherTypeFormalBounds.add (other.typeFormals[i].bound);
172176 }
173- return substitute (thisSubstitution, dropTypeFormals: true ) ==
174- other.substitute (otherSubstitution, dropTypeFormals: true );
177+ return const ListEquality ().equals (
178+ thisTypeFormalBounds.substitute (thisSubstitution) ??
179+ thisTypeFormalBounds,
180+ otherTypeFormalBounds.substitute (otherSubstitution) ??
181+ otherTypeFormalBounds) &&
182+ substitute (thisSubstitution, dropTypeFormals: true ) ==
183+ other.substitute (otherSubstitution, dropTypeFormals: true );
175184 } else {
176185 return returnType == other.returnType &&
177186 const ListEquality ()
@@ -212,6 +221,7 @@ class FunctionType extends Type
212221 }
213222 for (var typeFormal in typeFormals) {
214223 identifiers.add (typeFormal.name);
224+ typeFormal.explicitBound? .gatherUsedIdentifiers (identifiers);
215225 }
216226 for (var namedParameter in namedParameters) {
217227 // As explained in the documentation for `Type.gatherUsedIdentifiers`,
@@ -246,11 +256,43 @@ class FunctionType extends Type
246256 @override
247257 FunctionType ? substitute (Map <TypeParameter , Type > substitution,
248258 {bool dropTypeFormals = false }) {
259+ List <TypeParameter >? newTypeFormals;
260+ if (typeFormals.isNotEmpty) {
261+ if (dropTypeFormals) {
262+ newTypeFormals = const < TypeParameter > [];
263+ } else {
264+ // Check if any of the type formal bounds will be changed by the
265+ // substitution.
266+ if (typeFormals.any ((typeFormal) =>
267+ typeFormal.explicitBound? .substitute (substitution) != null )) {
268+ // Yes, at least one of the type formal bounds will be changed by the
269+ // substitution. So that type formal will have to be replaced by a
270+ // fresh one. Since type formal bounds can refer to other type
271+ // formals, other type formals might need to be replaced by fresh ones
272+ // too. To make things easier, go ahead and replace all the type
273+ // formals. Also, extend the substitution so that any references to
274+ // old type formals will be replaced by references to the new type
275+ // formals.
276+ substitution = {...substitution};
277+ newTypeFormals = [];
278+ for (var typeFormal in typeFormals) {
279+ var newTypeFormal = TypeParameter ._(typeFormal.name);
280+ newTypeFormals.add (newTypeFormal);
281+ substitution[typeFormal] = TypeParameterType (newTypeFormal);
282+ }
283+ // Now that the substitution has been created, fix up all the bounds.
284+ for (var i = 0 ; i < typeFormals.length; i++ ) {
285+ if (typeFormals[i].explicitBound case var bound? ) {
286+ newTypeFormals[i].explicitBound =
287+ bound.substitute (substitution) ?? bound;
288+ }
289+ }
290+ }
291+ }
292+ }
293+
249294 var newReturnType = returnType.substitute (substitution);
250295 var newPositionalParameters = positionalParameters.substitute (substitution);
251- var newTypeFormals = dropTypeFormals && ! typeFormals.isEmpty
252- ? const < TypeParameter > []
253- : null ;
254296 var newNamedParameters = namedParameters.substitute (substitution);
255297 if (newReturnType == null &&
256298 newPositionalParameters == null &&
@@ -277,7 +319,18 @@ class FunctionType extends Type
277319
278320 @override
279321 String _toStringWithoutSuffix ({required bool parenthesizeIfComplex}) {
280- var formals = typeFormals.isEmpty ? '' : '<${typeFormals .join (', ' )}>' ;
322+ var formals = '' ;
323+ if (typeFormals.isNotEmpty) {
324+ var formalStrings = < String > [];
325+ for (var typeFormal in typeFormals) {
326+ if (typeFormal.explicitBound case var bound? ) {
327+ formalStrings.add ('${typeFormal .name } extends $bound ' );
328+ } else {
329+ formalStrings.add (typeFormal.name);
330+ }
331+ }
332+ formals = '<${formalStrings .join (', ' )}>' ;
333+ }
281334 var parameters = < Object > [
282335 ...positionalParameters.sublist (0 , requiredPositionalParameterCount)
283336 ];
@@ -817,13 +870,17 @@ sealed class TypeNameInfo {
817870/// A type name that represents a type variable.
818871class TypeParameter extends TypeNameInfo
819872 implements SharedTypeParameterStructure <Type > {
820- /// The type variable's bound. Defaults to `Object?` .
821- @override
822- Type bound;
873+ /// The type variable's bound. If `null` , the bound is `Object?` .
874+ ///
875+ /// This is non-final because it needs to be possible to set it after
876+ /// construction, in order to create "F-bounded" type parameters (type
877+ /// parameters whose bound refers to the type parameter itself).
878+ Type ? explicitBound;
879+
880+ TypeParameter ._(super .name) : super (expectedRuntimeType: TypeParameterType );
823881
824- TypeParameter ._(super .name)
825- : bound = Type ('Object?' ),
826- super (expectedRuntimeType: TypeParameterType );
882+ @override
883+ Type get bound => explicitBound ?? Type ('Object?' );
827884
828885 @override
829886 String get displayName => name;
@@ -1673,7 +1730,7 @@ class VoidType extends _SpecialSimpleType
16731730/// meaning assigned to its identifiers yet.
16741731class _PreFunctionType extends _PreType {
16751732 final _PreType returnType;
1676- final List <TypeParameter > typeFormals;
1733+ final List <_PreTypeFormal > typeFormals;
16771734 final List <_PreType > positionalParameterTypes;
16781735 final int requiredPositionalParameterCount;
16791736 final List <_PreNamedFunctionParameter > namedParameters;
@@ -1687,11 +1744,23 @@ class _PreFunctionType extends _PreType {
16871744
16881745 @override
16891746 Type materialize ({required Map <String , TypeParameter > typeFormalScope}) {
1747+ List <TypeParameter > materializedTypeFormals;
16901748 if (typeFormals.isNotEmpty) {
1749+ materializedTypeFormals = < TypeParameter > [];
16911750 typeFormalScope = Map .of (typeFormalScope);
16921751 for (var typeFormal in typeFormals) {
1693- typeFormalScope[typeFormal.name] = typeFormal;
1752+ var materializedTypeFormal = TypeParameter ._(typeFormal.name);
1753+ materializedTypeFormals.add (materializedTypeFormal);
1754+ typeFormalScope[typeFormal.name] = materializedTypeFormal;
1755+ }
1756+ for (var i = 0 ; i < typeFormals.length; i++ ) {
1757+ if (typeFormals[i].bound case var bound? ) {
1758+ materializedTypeFormals[i].explicitBound =
1759+ bound.materialize (typeFormalScope: typeFormalScope);
1760+ }
16941761 }
1762+ } else {
1763+ materializedTypeFormals = const [];
16951764 }
16961765 return FunctionType (
16971766 returnType.materialize (typeFormalScope: typeFormalScope),
@@ -1700,7 +1769,7 @@ class _PreFunctionType extends _PreType {
17001769 positionalParameterType.materialize (
17011770 typeFormalScope: typeFormalScope)
17021771 ],
1703- typeFormals: typeFormals ,
1772+ typeFormals: materializedTypeFormals ,
17041773 requiredPositionalParameterCount: requiredPositionalParameterCount,
17051774 namedParameters: [
17061775 for (var namedParameter in namedParameters)
@@ -1846,6 +1915,15 @@ sealed class _PreType {
18461915 Type materialize ({required Map <String , TypeParameter > typeFormalScope});
18471916}
18481917
1918+ /// Representation of a formal parameter of a function type that has been parsed
1919+ /// but hasn't had meaning assigned to its identifiers yet.
1920+ class _PreTypeFormal {
1921+ final String name;
1922+ final _PreType ? bound;
1923+
1924+ _PreTypeFormal ({required this .name, required this .bound});
1925+ }
1926+
18491927/// Representation of a [Type] with a nullability suffix that has been parsed
18501928/// but hasn't had meaning assigned to its identifiers yet.
18511929class _PreTypeWithNullability extends _PreType {
@@ -2050,7 +2128,7 @@ class _TypeParser {
20502128 return _PrePromotedType (inner: type, promotion: promotion);
20512129 } else if (_currentToken == 'Function' ) {
20522130 _next ();
2053- List <TypeParameter > ? typeFormals;
2131+ List <_PreTypeFormal > typeFormals;
20542132 if (_currentToken == '<' ) {
20552133 typeFormals = _parseTypeFormals ();
20562134 } else {
@@ -2094,7 +2172,7 @@ class _TypeParser {
20942172 requiredPositionalParameterCount: requiredPositionalParameterCount ??
20952173 positionalParameterTypes.length,
20962174 namedParameters: namedFunctionParameters ?? const [],
2097- typeFormals: typeFormals ?? const [] );
2175+ typeFormals: typeFormals);
20982176 } else {
20992177 return null ;
21002178 }
@@ -2139,17 +2217,22 @@ class _TypeParser {
21392217 return result;
21402218 }
21412219
2142- List <TypeParameter > ? _parseTypeFormals () {
2220+ List <_PreTypeFormal > _parseTypeFormals () {
21432221 assert (_currentToken == '<' );
21442222 _next ();
2145- var typeFormals = < TypeParameter > [];
2223+ var typeFormals = < _PreTypeFormal > [];
21462224 while (true ) {
21472225 var name = _currentToken;
21482226 if (_identifierRegexp.matchAsPrefix (name) == null ) {
21492227 _parseFailure ('Expected an identifier' );
21502228 }
2151- typeFormals.add (TypeParameter ._(name));
21522229 _next ();
2230+ _PreType ? bound;
2231+ if (_currentToken == 'extends' ) {
2232+ _next ();
2233+ bound = _parseType ();
2234+ }
2235+ typeFormals.add (_PreTypeFormal (name: name, bound: bound));
21532236 if (_currentToken == ',' ) {
21542237 _next ();
21552238 continue ;
0 commit comments