diff options
| author | bors <bors@rust-lang.org> | 2024-02-14 01:23:46 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-02-14 01:23:46 +0000 |
| commit | 37b65339c8cf1d18e331f184dbf70bbddcb1e4f7 (patch) | |
| tree | c95decc6b714fb4fa448060f9764973a0496d808 | |
| parent | a84bb95a1f65bfe25038f188763a18e096a86ab2 (diff) | |
| parent | 38df5bdcf1fee2dc4a7a566afee0f0f161417701 (diff) | |
| download | rust-37b65339c8cf1d18e331f184dbf70bbddcb1e4f7.tar.gz rust-37b65339c8cf1d18e331f184dbf70bbddcb1e4f7.zip | |
Auto merge of #120942 - compiler-errors:deep-assoc-hang, r=lcnr
Ignore own item bounds in parent alias types in `for_each_item_bound` Fixes #120912 I want to get a vibe check on this approach, which is very obviously a hack, but I believe something that is forwards-compatible with a more thorough solution and "good enough for now". The problem here is that for a really deep rigid associated type, we are now repeatedly considering unrelated item bounds from the parent alias types, meaning we're doing a *lot* of extra work in the MIR inliner for deeply substituted rigid projections. This feels intimately related to #107614. In that PR, we split *supertrait* bounds (bound which share the same `Self` type as the predicate which is being elaborated) and *implied* bounds (anything that is implied by elaborating the predicate). The problem here is related to the fact that we don't maintain the split between these two for `item_bounds`. If we did, then when recursing into a parent alias type, we'd want to consider only the bounds that are given by [`PredicateFilter::All`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/astconv/enum.PredicateFilter.html#variant.SelfOnly) **except** those given by [`PredicateFilter::SelfOnly`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir_analysis/astconv/enum.PredicateFilter.html#variant.SelfOnly).
| -rw-r--r-- | compiler/rustc_trait_selection/src/traits/select/mod.rs | 16 |
1 files changed, 16 insertions, 0 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 185b735594f..ab0c53e6a9b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1605,6 +1605,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { on_ambiguity: impl FnOnce(), ) -> ControlFlow<T, ()> { let mut idx = 0; + let mut in_parent_alias_type = false; + loop { let (kind, alias_ty) = match *self_ty.kind() { ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), @@ -1618,6 +1620,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { for bound in self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) { + // HACK: On subsequent recursions, we only care about bounds that don't + // share the same type as `self_ty`. This is because for truly rigid + // projections, we will never be able to equate, e.g. `<T as Tr>::A` + // with `<<T as Tr>::A as Tr>::A`. + if in_parent_alias_type { + match bound.kind().skip_binder() { + ty::ClauseKind::Trait(tr) if tr.self_ty() == self_ty => continue, + ty::ClauseKind::Projection(p) if p.self_ty() == self_ty => continue, + _ => {} + } + } + for_each(self, bound, idx)?; idx += 1; } @@ -1627,6 +1641,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { return ControlFlow::Continue(()); } + + in_parent_alias_type = true; } } |
