@@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
167
167
// which is `O(nt)` where `t` is the depth of type-parameter constraints,
168
168
// remembering that `t` should be less than 7 in practice.
169
169
//
170
+ // FIXME(hkBst): the big-O bound above would be accurate for the number
171
+ // of calls to `parameters_for`, which itself is some O(complexity of type).
172
+ // That would make this potentially cubic instead of merely quadratic...
173
+ // ...unless we cache those `parameters_for` calls.
174
+ //
170
175
// Basically, I iterate over all projections and swap every
171
176
// "ready" projection to the start of the list, such that
172
177
// all of the projections before `i` are topologically sorted
173
178
// and constrain all the parameters in `input_parameters`.
174
179
//
175
- // In the example, `input_parameters` starts by containing `U` - which
176
- // is constrained by the trait-ref - and so on the first pass we
180
+ // In the first example, `input_parameters` starts by containing `U`,
181
+ // which is constrained by the self type `U`. Then, on the first pass we
177
182
// observe that `<U as Iterator>::Item = T` is a "ready" projection that
178
- // constrains `T` and swap it to front. As it is the sole projection,
183
+ // constrains `T` and swap it to the front. As it is the sole projection,
179
184
// no more swaps can take place afterwards, with the result being
180
185
// * <U as Iterator>::Item = T
181
186
// * T: Debug
@@ -193,33 +198,25 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
193
198
for j in i..predicates. len ( ) {
194
199
// Note that we don't have to care about binders here,
195
200
// as the impl trait ref never contains any late-bound regions.
196
- if let ty:: ClauseKind :: Projection ( projection) = predicates[ j] . 0 . kind ( ) . skip_binder ( ) {
197
- // Special case: watch out for some kind of sneaky attempt
198
- // to project out an associated type defined by this very
199
- // trait.
200
- let unbound_trait_ref = projection. projection_term . trait_ref ( tcx) ;
201
- if Some ( unbound_trait_ref) == impl_trait_ref {
202
- continue ;
203
- }
204
-
205
- // A projection depends on its input types and determines its output
206
- // type. For example, if we have
207
- // `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
208
- // Then the projection only applies if `T` is known, but it still
209
- // does not determine `U`.
210
- let inputs = parameters_for ( tcx, projection. projection_term , true ) ;
211
- let relies_only_on_inputs = inputs. iter ( ) . all ( |p| input_parameters. contains ( p) ) ;
212
- if !relies_only_on_inputs {
213
- continue ;
214
- }
201
+ if let ty:: ClauseKind :: Projection ( projection) = predicates[ j] . 0 . kind ( ) . skip_binder ( ) &&
202
+
203
+ // Special case: watch out for some kind of sneaky attempt to
204
+ // project out an associated type defined by this very trait.
205
+ !impl_trait_ref. is_some_and ( |t| t == projection. projection_term . trait_ref ( tcx) ) &&
206
+
207
+ // A projection depends on its input types and determines its output
208
+ // type. For example, if we have
209
+ // `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
210
+ // then the projection only applies if `T` is known, but it still
211
+ // does not determine `U`.
212
+ parameters_for ( tcx, projection. projection_term , true ) . iter ( ) . all ( |p| input_parameters. contains ( p) )
213
+ {
215
214
input_parameters. extend ( parameters_for ( tcx, projection. term , false ) ) ;
216
- } else {
217
- continue ;
215
+
216
+ predicates. swap ( i, j) ;
217
+ i += 1 ;
218
+ changed = true ;
218
219
}
219
- // fancy control flow to bypass borrow checker
220
- predicates. swap ( i, j) ;
221
- i += 1 ;
222
- changed = true ;
223
220
}
224
221
debug ! (
225
222
"setup_constraining_predicates: predicates={:?} \
0 commit comments