@@ -130,6 +130,30 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
130130 return result;
131131 }
132132
133+ @override
134+ void eliminateTypeParametersInGeneratedConstraints (
135+ covariant List <TypeParameterElement > eliminator,
136+ shared.TypeConstraintGeneratorState eliminationStartState,
137+ {required AstNode ? astNodeForTesting}) {
138+ var constraints = _constraints.sublist (eliminationStartState.count);
139+ _constraints.length = eliminationStartState.count;
140+ for (var constraint in constraints) {
141+ if (constraint.isUpper) {
142+ addUpperConstraintForParameter (
143+ constraint.typeParameter,
144+ typeAnalyzerOperations.leastClosureOfTypeInternal (
145+ constraint.constraint.unwrapTypeSchemaView (), eliminator),
146+ nodeForTesting: astNodeForTesting);
147+ } else {
148+ addLowerConstraintForParameter (
149+ constraint.typeParameter,
150+ typeAnalyzerOperations.greatestClosureOfTypeInternal (
151+ constraint.constraint.unwrapTypeSchemaView (), eliminator),
152+ nodeForTesting: astNodeForTesting);
153+ }
154+ }
155+ }
156+
133157 @override
134158 List <DartType >? getTypeArgumentsAsInstanceOf (
135159 InterfaceType type, InterfaceElement typeDeclaration) {
@@ -144,6 +168,43 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
144168 return null ;
145169 }
146170
171+ @override
172+ (DartType , DartType , {List <TypeParameterElement > typeParametersToEliminate})
173+ instantiateFunctionTypesAndProvideFreshTypeParameters (
174+ covariant FunctionType P , covariant FunctionType Q ,
175+ {required bool leftSchema}) {
176+ // And `Z0...Zn` are fresh variables with bounds `B20, ..., B2n`.
177+ // Where `B2i` is `B0i[Z0/T0, ..., Zn/Tn]` if `P` is a type schema.
178+ // Or `B2i` is `B1i[Z0/S0, ..., Zn/Sn]` if `Q` is a type schema.
179+ // In other words, we choose the bounds for the fresh variables from
180+ // whichever of the two generic function types is a type schema and does
181+ // not contain any variables from `L`.
182+ var newTypeParameters = < TypeParameterElement > [];
183+ for (var i = 0 ; i < P .typeFormals.length; i++ ) {
184+ var Z = TypeParameterElementImpl ('Z$i ' , - 1 );
185+ if (leftSchema) {
186+ Z .bound = P .typeFormals[i].bound;
187+ } else {
188+ Z .bound = Q .typeFormals[i].bound;
189+ }
190+ newTypeParameters.add (Z );
191+ }
192+
193+ // And `F0[Z0/T0, ..., Zn/Tn]` is a subtype match for
194+ // `F1[Z0/S0, ..., Zn/Sn]` with respect to `L` under constraints `C0`.
195+ var typeArguments = newTypeParameters
196+ .map ((e) => e.instantiate (nullabilitySuffix: NullabilitySuffix .none))
197+ .toList ();
198+ var P_instantiated = P .instantiate (typeArguments);
199+ var Q_instantiated = Q .instantiate (typeArguments);
200+
201+ return (
202+ P_instantiated ,
203+ Q_instantiated ,
204+ typeParametersToEliminate: newTypeParameters
205+ );
206+ }
207+
147208 @override
148209 bool performSubtypeConstraintGenerationInternal (DartType p, DartType q,
149210 {required bool leftSchema, required AstNode ? astNodeForTesting}) {
@@ -299,8 +360,9 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
299360 }
300361 }
301362
302- if (P is FunctionType && Q is FunctionType ) {
303- return _functionType (P , Q , leftSchema, nodeForTesting: nodeForTesting);
363+ if (performSubtypeConstraintGenerationForFunctionTypes (P , Q ,
364+ leftSchema: leftSchema, astNodeForTesting: nodeForTesting)) {
365+ return true ;
304366 }
305367
306368 // A type `P` is a subtype match for `Record` with respect to `L` under no
@@ -319,96 +381,6 @@ class TypeConstraintGatherer extends shared.TypeConstraintGenerator<
319381
320382 return false ;
321383 }
322-
323- /// Matches [P] against [Q] , where [P] and [Q] are both function types.
324- ///
325- /// If [P] is a subtype of [Q] under some constraints, the constraints making
326- /// the relation possible are recorded to [_constraints] , and `true` is
327- /// returned. Otherwise, [_constraints] is left unchanged (or rolled back),
328- /// and `false` is returned.
329- bool _functionType (FunctionType P , FunctionType Q , bool leftSchema,
330- {required AstNode ? nodeForTesting}) {
331- if (P .nullabilitySuffix != NullabilitySuffix .none) {
332- return false ;
333- }
334-
335- if (Q .nullabilitySuffix != NullabilitySuffix .none) {
336- return false ;
337- }
338-
339- var P_typeFormals = P .typeFormals;
340- var Q_typeFormals = Q .typeFormals;
341- if (P_typeFormals .length != Q_typeFormals .length) {
342- return false ;
343- }
344-
345- if (P_typeFormals .isEmpty && Q_typeFormals .isEmpty) {
346- return performSubtypeConstraintGenerationForFunctionTypes (P , Q ,
347- leftSchema: leftSchema, astNodeForTesting: nodeForTesting);
348- }
349-
350- // We match two generic function types:
351- // `<T0 extends B00, ..., Tn extends B0n>F0`
352- // `<S0 extends B10, ..., Sn extends B1n>F1`
353- // with respect to `L` under constraint set `C2`:
354- var rewind = _constraints.length;
355-
356- // If `B0i` is a subtype match for `B1i` with constraint set `Ci0`.
357- // If `B1i` is a subtype match for `B0i` with constraint set `Ci1`.
358- // And `Ci2` is `Ci0 + Ci1`.
359- for (var i = 0 ; i < P_typeFormals .length; i++ ) {
360- var B0 = P_typeFormals [i].bound ?? _typeSystem.objectQuestion;
361- var B1 = Q_typeFormals [i].bound ?? _typeSystem.objectQuestion;
362- if (! trySubtypeMatch (B0 , B1 , leftSchema,
363- nodeForTesting: nodeForTesting)) {
364- _constraints.length = rewind;
365- return false ;
366- }
367- if (! trySubtypeMatch (B1 , B0 , ! leftSchema,
368- nodeForTesting: nodeForTesting)) {
369- _constraints.length = rewind;
370- return false ;
371- }
372- }
373-
374- // And `Z0...Zn` are fresh variables with bounds `B20, ..., B2n`.
375- // Where `B2i` is `B0i[Z0/T0, ..., Zn/Tn]` if `P` is a type schema.
376- // Or `B2i` is `B1i[Z0/S0, ..., Zn/Sn]` if `Q` is a type schema.
377- // In other words, we choose the bounds for the fresh variables from
378- // whichever of the two generic function types is a type schema and does
379- // not contain any variables from `L`.
380- var newTypeParameters = < TypeParameterElement > [];
381- for (var i = 0 ; i < P_typeFormals .length; i++ ) {
382- var Z = TypeParameterElementImpl ('Z$i ' , - 1 );
383- if (leftSchema) {
384- Z .bound = P_typeFormals [i].bound;
385- } else {
386- Z .bound = Q_typeFormals [i].bound;
387- }
388- newTypeParameters.add (Z );
389- }
390-
391- // And `F0[Z0/T0, ..., Zn/Tn]` is a subtype match for
392- // `F1[Z0/S0, ..., Zn/Sn]` with respect to `L` under constraints `C0`.
393- var typeArguments = newTypeParameters
394- .map ((e) => e.instantiate (nullabilitySuffix: NullabilitySuffix .none))
395- .toList ();
396- var P_instantiated = P .instantiate (typeArguments);
397- var Q_instantiated = Q .instantiate (typeArguments);
398- if (! performSubtypeConstraintGenerationForFunctionTypes (
399- P_instantiated , Q_instantiated ,
400- leftSchema: leftSchema, astNodeForTesting: nodeForTesting)) {
401- _constraints.length = rewind;
402- return false ;
403- }
404-
405- // And `C1` is `C02 + ... + Cn2 + C0`.
406- // And `C2` is `C1` with each constraint replaced with its closure
407- // with respect to `[Z0, ..., Zn]`.
408- // TODO(scheglov): do closure
409-
410- return true ;
411- }
412384}
413385
414386/// Data structure maintaining intermediate type inference results, such as
0 commit comments