Skip to content

Commit 4acea46

Browse files
committed
simplify setup_constraining_predicates, and note it is potentially cubic
1 parent 4056082 commit 4acea46

File tree

1 file changed

+26
-26
lines changed

1 file changed

+26
-26
lines changed

compiler/rustc_hir_analysis/src/constrained_generic_params.rs

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,20 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
167167
// which is `O(nt)` where `t` is the depth of type-parameter constraints,
168168
// remembering that `t` should be less than 7 in practice.
169169
//
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+
//
170175
// Basically, I iterate over all projections and swap every
171176
// "ready" projection to the start of the list, such that
172177
// all of the projections before `i` are topologically sorted
173178
// and constrain all the parameters in `input_parameters`.
174179
//
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
177182
// 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,
179184
// no more swaps can take place afterwards, with the result being
180185
// * <U as Iterator>::Item = T
181186
// * T: Debug
@@ -193,33 +198,28 @@ pub(crate) fn setup_constraining_predicates<'tcx>(
193198
for j in i..predicates.len() {
194199
// Note that we don't have to care about binders here,
195200
// 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`.
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+
{
210213
let inputs = parameters_for(tcx, projection.projection_term, true);
211214
let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
212-
if !relies_only_on_inputs {
213-
continue;
214-
}
215+
relies_only_on_inputs
216+
} {
215217
input_parameters.extend(parameters_for(tcx, projection.term, false));
216-
} else {
217-
continue;
218+
219+
predicates.swap(i, j);
220+
i += 1;
221+
changed = true;
218222
}
219-
// fancy control flow to bypass borrow checker
220-
predicates.swap(i, j);
221-
i += 1;
222-
changed = true;
223223
}
224224
debug!(
225225
"setup_constraining_predicates: predicates={:?} \

0 commit comments

Comments
 (0)