@@ -56,12 +56,34 @@ class GenericInferrer {
56
56
final Set <TypeParameterElement > _typeParameters = Set .identity ();
57
57
final Map <TypeParameterElement , List <_TypeConstraint >> _constraints = {};
58
58
59
- GenericInferrer (
60
- this ._typeSystem,
61
- Iterable <TypeParameterElement > typeFormals,
62
- ) {
63
- _typeParameters.addAll (typeFormals);
64
- for (var formal in typeFormals) {
59
+ /// The list of type parameters being inferred.
60
+ final List <TypeParameterElement > _typeFormals;
61
+
62
+ /// Indicates whether type parameter bounds should be included in constraints.
63
+ final bool considerExtendsClause;
64
+
65
+ /// The [ErrorReporter] to which inference errors should be reported, or
66
+ /// `null` if errors shouldn't be reported.
67
+ final ErrorReporter ? errorReporter;
68
+
69
+ /// The [AstNode] to which errors should be attached. May be `null` if errors
70
+ /// are not being reported (that is, if [errorReporter] is also `null` ).
71
+ final AstNode ? errorNode;
72
+
73
+ /// Indicates whether the "generic metadata" feature is enabled. When it is,
74
+ /// type arguments are allowed to be instantiated with generic function types.
75
+ final bool genericMetadataIsEnabled;
76
+
77
+ GenericInferrer (this ._typeSystem, this ._typeFormals,
78
+ {this .considerExtendsClause = true ,
79
+ this .errorReporter,
80
+ this .errorNode,
81
+ required this .genericMetadataIsEnabled}) {
82
+ if (errorReporter != null ) {
83
+ assert (errorNode != null );
84
+ }
85
+ _typeParameters.addAll (_typeFormals);
86
+ for (var formal in _typeFormals) {
65
87
_constraints[formal] = [];
66
88
}
67
89
}
@@ -85,6 +107,24 @@ class GenericInferrer {
85
107
tryMatchSubtypeOf (argumentType, parameterType, origin, covariant : false );
86
108
}
87
109
110
+ /// Applies all the argument constraints implied by [parameters] and
111
+ /// [argumentTypes] .
112
+ void constrainArguments (
113
+ {ClassElement ? genericClass,
114
+ required List <ParameterElement > parameters,
115
+ required List <DartType > argumentTypes}) {
116
+ for (int i = 0 ; i < argumentTypes.length; i++ ) {
117
+ // Try to pass each argument to each parameter, recording any type
118
+ // parameter bounds that were implied by this assignment.
119
+ constrainArgument (
120
+ argumentTypes[i],
121
+ parameters[i].type,
122
+ parameters[i].name,
123
+ genericClass: genericClass,
124
+ );
125
+ }
126
+ }
127
+
88
128
/// Constrain a universal function type [fnType] used in a context
89
129
/// [contextType] .
90
130
void constrainGenericFunctionInContext (
@@ -117,67 +157,46 @@ class GenericInferrer {
117
157
tryMatchSubtypeOf (declaredType, contextType, origin, covariant : true );
118
158
}
119
159
120
- /// Given the constraints that were given by calling [constrainArgument] and
121
- /// [constrainReturnType] , find the type arguments for the [typeFormals] that
122
- /// satisfies these constraints.
123
- ///
124
- /// If [downwardsInferPhase] is set, we are in the first pass of inference,
125
- /// pushing context types down. At that point we are allowed to push down
126
- /// `_` to precisely represent an unknown type. If [downwardsInferPhase] is
127
- /// false, we are on our final inference pass, have all available information
128
- /// including argument types, and must not conclude `_` for any type formal.
129
- List <DartType >? infer (
130
- List <TypeParameterElement > typeFormals, {
131
- bool considerExtendsClause = true ,
132
- ErrorReporter ? errorReporter,
133
- AstNode ? errorNode,
134
- bool failAtError = false ,
135
- bool downwardsInferPhase = false ,
136
- required bool genericMetadataIsEnabled,
137
- }) {
138
- // Initialize the inferred type array.
139
- //
140
- // In the downwards phase, they all start as `_` to offer reasonable
141
- // degradation for f-bounded type parameters.
142
- var inferredTypes =
143
- List <DartType >.filled (typeFormals.length, UnknownInferredType .instance);
160
+ /// Performs downwards inference, producing a set of inferred types that may
161
+ /// contain references to the "unknown type".
162
+ List <DartType > downwardsInfer () => _chooseTypes (downwardsInferPhase: true );
144
163
145
- for (int i = 0 ; i < typeFormals.length; i++ ) {
146
- // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
147
- // variance is added to the interface.
148
- var typeParam = typeFormals[i] as TypeParameterElementImpl ;
149
- _TypeConstraint ? extendsClause;
150
- var bound = typeParam.bound;
151
- if (considerExtendsClause && bound != null ) {
152
- extendsClause = _TypeConstraint .fromExtends (
153
- typeParam,
154
- bound,
155
- Substitution .fromPairs (typeFormals, inferredTypes)
156
- .substituteType (bound),
157
- isNonNullableByDefault: isNonNullableByDefault,
158
- );
164
+ /// Tries to make [i1] a subtype of [i2] and accumulate constraints as needed.
165
+ ///
166
+ /// The return value indicates whether the match was successful. If it was
167
+ /// unsuccessful, any constraints that were accumulated during the match
168
+ /// attempt have been rewound (see [_rewindConstraints] ).
169
+ bool tryMatchSubtypeOf (DartType t1, DartType t2, _TypeConstraintOrigin origin,
170
+ {required bool covariant }) {
171
+ var gatherer = TypeConstraintGatherer (
172
+ typeSystem: _typeSystem, typeParameters: _typeParameters);
173
+ var success = gatherer.trySubtypeMatch (t1, t2, ! covariant );
174
+ if (success) {
175
+ var constraints = gatherer.computeConstraints ();
176
+ for (var entry in constraints.entries) {
177
+ if (! entry.value.isEmpty) {
178
+ var constraint = _constraints[entry.key]! ;
179
+ constraint.add (
180
+ _TypeConstraint (origin, entry.key,
181
+ lower: entry.value.lower, upper: entry.value.upper),
182
+ );
183
+ }
159
184
}
160
-
161
- var constraints = _constraints[typeParam]! ;
162
- inferredTypes[i] = downwardsInferPhase
163
- ? _inferTypeParameterFromContext (constraints, extendsClause,
164
- isContravariant: typeParam.variance.isContravariant)
165
- : _inferTypeParameterFromAll (constraints, extendsClause,
166
- isContravariant: typeParam.variance.isContravariant,
167
- preferUpwardsInference: ! typeParam.isLegacyCovariant);
168
185
}
169
186
170
- // If the downwards infer phase has failed, we'll catch this in the upwards
171
- // phase later on.
172
- if (downwardsInferPhase) {
173
- return inferredTypes;
174
- }
187
+ return success;
188
+ }
175
189
190
+ /// Same as [upwardsInfer] , but if [failAtError] is `true` (the default) and
191
+ /// inference fails, returns `null` rather than trying to perform error
192
+ /// recovery.
193
+ List <DartType >? tryUpwardsInfer ({bool failAtError = true }) {
194
+ var inferredTypes = _chooseTypes (downwardsInferPhase: false );
176
195
// Check the inferred types against all of the constraints.
177
196
var knownTypes = < TypeParameterElement , DartType > {};
178
197
var hasErrorReported = false ;
179
- for (int i = 0 ; i < typeFormals .length; i++ ) {
180
- TypeParameterElement parameter = typeFormals [i];
198
+ for (int i = 0 ; i < _typeFormals .length; i++ ) {
199
+ TypeParameterElement parameter = _typeFormals [i];
181
200
var constraints = _constraints[parameter]! ;
182
201
183
202
var inferred = inferredTypes[i];
@@ -189,7 +208,7 @@ class GenericInferrer {
189
208
var parameterBoundRaw = parameter.bound;
190
209
if (parameterBoundRaw != null ) {
191
210
var parameterBound =
192
- Substitution .fromPairs (typeFormals , inferredTypes)
211
+ Substitution .fromPairs (_typeFormals , inferredTypes)
193
212
.substituteType (parameterBoundRaw);
194
213
parameterBound = _toLegacyElementIfOptOut (parameterBound);
195
214
var extendsConstraint = _TypeConstraint .fromExtends (
@@ -225,7 +244,7 @@ class GenericInferrer {
225
244
hasErrorReported = true ;
226
245
var typeFormals = inferred.typeFormals;
227
246
var typeFormalsStr = typeFormals.map (_elementStr).join (', ' );
228
- errorReporter.reportErrorForNode (
247
+ errorReporter! .reportErrorForNode (
229
248
CompileTimeErrorCode .COULD_NOT_INFER , errorNode! , [
230
249
parameter.name,
231
250
' Inferred candidate type ${_typeStr (inferred )} has type parameters'
@@ -250,17 +269,17 @@ class GenericInferrer {
250
269
}
251
270
252
271
// Use instantiate to bounds to finish things off.
253
- var hasError = List <bool >.filled (typeFormals .length, false );
254
- var result = _typeSystem.instantiateTypeFormalsToBounds (typeFormals ,
272
+ var hasError = List <bool >.filled (_typeFormals .length, false );
273
+ var result = _typeSystem.instantiateTypeFormalsToBounds (_typeFormals ,
255
274
hasError: hasError, knownTypes: knownTypes);
256
275
257
276
// Report any errors from instantiateToBounds.
258
277
for (int i = 0 ; i < hasError.length; i++ ) {
259
278
if (hasError[i]) {
260
279
if (failAtError) return null ;
261
280
hasErrorReported = true ;
262
- TypeParameterElement typeParam = typeFormals [i];
263
- var typeParamBound = Substitution .fromPairs (typeFormals , inferredTypes)
281
+ TypeParameterElement typeParam = _typeFormals [i];
282
+ var typeParamBound = Substitution .fromPairs (_typeFormals , inferredTypes)
264
283
.substituteType (typeParam.bound ?? typeProvider.objectType);
265
284
// TODO(jmesserly): improve this error message.
266
285
errorReporter? .reportErrorForNode (
@@ -277,7 +296,6 @@ class GenericInferrer {
277
296
_checkArgumentsNotMatchingBounds (
278
297
errorNode: errorNode,
279
298
errorReporter: errorReporter,
280
- typeParameters: typeFormals,
281
299
typeArguments: result,
282
300
);
283
301
}
@@ -286,47 +304,18 @@ class GenericInferrer {
286
304
return result;
287
305
}
288
306
289
- /// Tries to make [i1] a subtype of [i2] and accumulate constraints as needed.
290
- ///
291
- /// The return value indicates whether the match was successful. If it was
292
- /// unsuccessful, any constraints that were accumulated during the match
293
- /// attempt have been rewound (see [_rewindConstraints] ).
294
- bool tryMatchSubtypeOf (DartType t1, DartType t2, _TypeConstraintOrigin origin,
295
- {required bool covariant }) {
296
- var gatherer = TypeConstraintGatherer (
297
- typeSystem: _typeSystem,
298
- typeParameters: _typeParameters,
299
- );
300
- var success = gatherer.trySubtypeMatch (t1, t2, ! covariant );
301
- if (success) {
302
- var constraints = gatherer.computeConstraints ();
303
- for (var entry in constraints.entries) {
304
- if (! entry.value.isEmpty) {
305
- var constraint = _constraints[entry.key]! ;
306
- constraint.add (
307
- _TypeConstraint (
308
- origin,
309
- entry.key,
310
- lower: entry.value.lower,
311
- upper: entry.value.upper,
312
- ),
313
- );
314
- }
315
- }
316
- }
317
-
318
- return success;
319
- }
307
+ /// Performs upwards inference, producing a final set of inferred types that
308
+ /// does not contain references to the "unknown type".
309
+ List <DartType > upwardsInfer () => tryUpwardsInfer (failAtError: false )! ;
320
310
321
311
/// Check that inferred [typeArguments] satisfy the [typeParameters] bounds.
322
312
void _checkArgumentsNotMatchingBounds ({
323
313
required AstNode ? errorNode,
324
314
required ErrorReporter ? errorReporter,
325
- required List <TypeParameterElement > typeParameters,
326
315
required List <DartType > typeArguments,
327
316
}) {
328
- for (int i = 0 ; i < typeParameters .length; i++ ) {
329
- var parameter = typeParameters [i];
317
+ for (int i = 0 ; i < _typeFormals .length; i++ ) {
318
+ var parameter = _typeFormals [i];
330
319
var argument = typeArguments[i];
331
320
332
321
var rawBound = parameter.bound;
@@ -335,7 +324,7 @@ class GenericInferrer {
335
324
}
336
325
rawBound = _typeSystem.toLegacyTypeIfOptOut (rawBound);
337
326
338
- var substitution = Substitution .fromPairs (typeParameters , typeArguments);
327
+ var substitution = Substitution .fromPairs (_typeFormals , typeArguments);
339
328
var bound = substitution.substituteType (rawBound);
340
329
if (! _typeSystem.isSubtypeOf (argument, bound)) {
341
330
errorReporter? .reportErrorForNode (
@@ -438,6 +427,38 @@ class GenericInferrer {
438
427
}
439
428
}
440
429
430
+ /// Computes (or recomputes) a set of [inferredTypes] based on the constraints
431
+ /// that have been recorded so far.
432
+ List <DartType > _chooseTypes ({required bool downwardsInferPhase}) {
433
+ var inferredTypes = List <DartType >.filled (
434
+ _typeFormals.length, UnknownInferredType .instance);
435
+ for (int i = 0 ; i < _typeFormals.length; i++ ) {
436
+ // TODO (kallentu) : Clean up TypeParameterElementImpl casting once
437
+ // variance is added to the interface.
438
+ var typeParam = _typeFormals[i] as TypeParameterElementImpl ;
439
+ _TypeConstraint ? extendsClause;
440
+ var bound = typeParam.bound;
441
+ if (considerExtendsClause && bound != null ) {
442
+ extendsClause = _TypeConstraint .fromExtends (
443
+ typeParam,
444
+ bound,
445
+ Substitution .fromPairs (_typeFormals, inferredTypes)
446
+ .substituteType (bound),
447
+ isNonNullableByDefault: isNonNullableByDefault);
448
+ }
449
+
450
+ var constraints = _constraints[typeParam]! ;
451
+ inferredTypes[i] = downwardsInferPhase
452
+ ? _inferTypeParameterFromContext (constraints, extendsClause,
453
+ isContravariant: typeParam.variance.isContravariant)
454
+ : _inferTypeParameterFromAll (constraints, extendsClause,
455
+ isContravariant: typeParam.variance.isContravariant,
456
+ preferUpwardsInference: ! typeParam.isLegacyCovariant);
457
+ }
458
+
459
+ return inferredTypes;
460
+ }
461
+
441
462
String _elementStr (Element element) {
442
463
return element.getDisplayString (withNullability: isNonNullableByDefault);
443
464
}
0 commit comments