From 207667ba12f31f7579d3d9da58d30370fc9bfc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 8 Jun 2026 02:27:48 +0200 Subject: [PATCH 1/2] Simplify the HIR ty lowering of elided trait object lifetime bounds Letting `lower_lifetime` check `tcx.named_bound_var` & call `re_infer` just means we now end up passing `lifetime.ident.span` to `re_infer` instead of the `span` of the trait object type. However, 1. in the case of `LifetimeKind::ImplicitObjectLifetimeDefault` `lifetime.ident.span` is actually equal to said span. 2. in the case of `LifetimeKind::Infer` the span now makes more sense; consider `dyn Trait + '_` where the span now just contains the `'_` not the entire type which is just better. --- .../src/hir_ty_lowering/dyn_trait.rs | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 818c418ad7c60..8aa9c53d49e5e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -446,19 +446,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let region_bound = if !lifetime.is_elided() { self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) } else { + // Curiously, we also use the *object region bound* for `Infer` (`'_`) + // while we obviously don't use the *object lifetime default* for it... self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - // Curiously, we prefer object lifetime default for `+ '_`... - if tcx.named_bound_var(lifetime.hir_id).is_some() { - self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) + let reason = if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind + { + RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi()) } else { - let reason = - if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind { - RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi()) - } else { - RegionInferReason::ExplicitObjectLifetime - }; - self.re_infer(span, reason) - } + RegionInferReason::ExplicitObjectLifetime + }; + + self.lower_lifetime(lifetime, reason) }) }; debug!(?region_bound); From 6b234eb78b2e88981c03eb9ba84e1211a158aeaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Mon, 8 Jun 2026 02:09:10 +0200 Subject: [PATCH 2/2] Match on `lifetime.kind` explicitly instead of calling `lifetime.is_infer` This makes it really obvious that we're computing object region bounds for `Infer`, too, not just for `ImplicitObjectLifetimeDefault` which was really hard to see beforehand. It's unclear to me whether this was intentional or not, needs investigation. Introduce method `lower_trait_object_lifetime` to allow usage of early returns to make the control flow clearer compared to the `unwrap_or_else`. --- .../src/hir_ty_lowering/dyn_trait.rs | 47 +++++++++++-------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs index 8aa9c53d49e5e..fea7b48e03a0f 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_trait.rs @@ -434,34 +434,41 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // N.b. principal, projections, auto traits // FIXME: This is actually wrong with multiple principals in regards to symbol mangling - let mut v = principal_trait_ref + let mut predicates = principal_trait_ref .into_iter() .chain(existential_projections) .chain(auto_trait_predicates) .collect::>(); - v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - let existential_predicates = tcx.mk_poly_existential_predicates(&v); + predicates.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + let predicates = tcx.mk_poly_existential_predicates(&predicates); - // Use explicitly-specified region bound, unless the bound is missing. - let region_bound = if !lifetime.is_elided() { - self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime) - } else { - // Curiously, we also use the *object region bound* for `Infer` (`'_`) - // while we obviously don't use the *object lifetime default* for it... - self.compute_object_lifetime_bound(span, existential_predicates).unwrap_or_else(|| { - let reason = if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind - { - RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi()) - } else { - RegionInferReason::ExplicitObjectLifetime - }; + let region_bound = self.lower_trait_object_lifetime(lifetime, predicates, span); - self.lower_lifetime(lifetime, reason) - }) + Ty::new_dynamic(tcx, predicates, region_bound) + } + + fn lower_trait_object_lifetime( + &self, + lifetime: &hir::Lifetime, + predicates: &'tcx ty::List>, + span: Span, + ) -> ty::Region<'tcx> { + // Curiously, we also use the *object region bound* for `Infer` (`'_`) + // while we obviously don't use the *object lifetime default* for it... + if let hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer = + lifetime.kind + && let Some(region) = self.compute_object_lifetime_bound(span, predicates) + { + return region; + } + + let reason = if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind { + RegionInferReason::ObjectLifetimeDefault(span.shrink_to_hi()) + } else { + RegionInferReason::ExplicitObjectLifetime }; - debug!(?region_bound); - Ty::new_dynamic(tcx, existential_predicates, region_bound) + self.lower_lifetime(lifetime, reason) } /// Check that elaborating the principal of a trait ref doesn't lead to projections