From 82a4049844cfa328aa903afe78a974a5385a2c76 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 18 Jun 2025 17:03:15 +0000 Subject: [PATCH] hir_analysis: add missing sizedness bounds Default sizedness bounds were not being added to `explicit_super_predicates_of` and `explicit_implied_predicates_of` which meant that a trait bound added to a associated type projection would be missing the implied predicate of the default sizedness supertrait of that trait. An unexpected consequence of this change was that the check for multiple principals was now finding an additional `MetaSized` principal when eagerly expanding trait aliases. Instead of special-casing trait aliases as different from traits and not adding a `MetaSized` supertrait to trait aliases, filter out `MetaSized` when lowering `dyn Trait`. --- .../src/collect/item_bounds.rs | 30 +++- .../src/collect/predicates_of.rs | 34 ++-- .../src/hir_ty_lowering/bounds.rs | 163 ++++++++---------- .../src/hir_ty_lowering/dyn_trait.rs | 23 ++- .../src/hir_ty_lowering/mod.rs | 18 +- .../bound-on-assoc-type-projection.rs | 18 ++ .../ui/sized-hierarchy/default-supertrait.rs | 5 +- .../sized-hierarchy/default-supertrait.stderr | 37 +--- .../ui/sized-hierarchy/elaboration-simple.rs | 13 ++ .../trait-alias-elaboration.rs | 16 ++ .../trait-alias-elaboration.stderr | 17 ++ .../normalize/normalize-param-env-2.stderr | 19 +- .../normalize-param-env-4.next.stderr | 16 +- 13 files changed, 215 insertions(+), 194 deletions(-) create mode 100644 tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs create mode 100644 tests/ui/sized-hierarchy/elaboration-simple.rs create mode 100644 tests/ui/sized-hierarchy/trait-alias-elaboration.rs create mode 100644 tests/ui/sized-hierarchy/trait-alias-elaboration.stderr diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 67284e1621568..6b51e31579616 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -12,7 +12,9 @@ use tracing::{debug, instrument}; use super::ItemCtxt; use super::predicates_of::assert_only_contains_predicates_from; -use crate::hir_ty_lowering::{HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter}; +use crate::hir_ty_lowering::{ + HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, +}; /// For associated types we include both bounds written on the type /// (`type X: Trait`) and predicates from the trait: `where Self::X: Trait`. @@ -52,15 +54,20 @@ fn associated_type_bounds<'tcx>( | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { // Implicit bounds are added to associated types unless a `?Trait` bound is found. - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( + &mut bounds, + item_ty, + hir_bounds, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, + span, + ); + icx.lowerer().add_default_traits( &mut bounds, item_ty, hir_bounds, - None, - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); - icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); // Also collect `where Self::Assoc: Trait` from the parent trait's where clauses. let trait_def_id = tcx.local_parent(assoc_item_def_id); @@ -372,15 +379,20 @@ fn opaque_type_bounds<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( + &mut bounds, + item_ty, + hir_bounds, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, + span, + ); + icx.lowerer().add_default_traits( &mut bounds, item_ty, hir_bounds, - None, - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); - icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span); } //`ConstIfConst` is only interested in `[const]` bounds. PredicateFilter::ConstIfConst | PredicateFilter::SelfConstIfConst => {} diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e66accc7dcffd..79aaa0cb79701 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -19,7 +19,8 @@ use crate::collect::ItemCtxt; use crate::constrained_generic_params as cgp; use crate::delegation::inherit_predicates_for_delegation_item; use crate::hir_ty_lowering::{ - HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, + HirTyLowerer, ImpliedBoundsContext, OverlappingAsssocItemConstraints, PredicateFilter, + RegionInferReason, }; /// Returns a list of all type predicates (explicit and implicit) for the definition with @@ -189,19 +190,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, tcx.types.self_param, self_bounds, - None, - Some(def_id), + ImpliedBoundsContext::TraitDef(def_id), span, ); - icx.lowerer().add_default_super_traits( - def_id, + icx.lowerer().add_default_traits( &mut bounds, + tcx.types.self_param, self_bounds, - hir_generics, + ImpliedBoundsContext::TraitDef(def_id), span, ); predicates.extend(bounds); @@ -229,19 +229,18 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen let param_ty = icx.lowerer().lower_ty_param(param.hir_id); let mut bounds = Vec::new(); // Implicit bounds are added to type params unless a `?Trait` bound is found - icx.lowerer().add_sizedness_bounds( + icx.lowerer().add_implicit_sizedness_bounds( &mut bounds, param_ty, &[], - Some((param.def_id, hir_generics.predicates)), - None, + ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, ); icx.lowerer().add_default_traits( &mut bounds, param_ty, &[], - Some((param.def_id, hir_generics.predicates)), + ImpliedBoundsContext::TyParam(param.def_id, hir_generics.predicates), param.span, ); trace!(?bounds); @@ -676,11 +675,18 @@ pub(super) fn implied_predicates_with_filter<'tcx>( | PredicateFilter::SelfOnly | PredicateFilter::SelfTraitThatDefines(_) | PredicateFilter::SelfAndAssociatedTypeBounds => { - icx.lowerer().add_default_super_traits( - trait_def_id, + icx.lowerer().add_implicit_sizedness_bounds( + &mut bounds, + self_param_ty, + superbounds, + ImpliedBoundsContext::TraitDef(trait_def_id), + item.span, + ); + icx.lowerer().add_default_traits( &mut bounds, + self_param_ty, superbounds, - generics, + ImpliedBoundsContext::TraitDef(trait_def_id), item.span, ); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs index a3cb49e32d808..1832e6e890b9b 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs @@ -1,4 +1,3 @@ -use std::assert_matches::assert_matches; use std::ops::ControlFlow; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; @@ -7,7 +6,7 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::PolyTraitRef; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; +use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_middle::bug; use rustc_middle::ty::{ self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -18,11 +17,10 @@ use rustc_trait_selection::traits; use smallvec::SmallVec; use tracing::{debug, instrument}; -use super::errors::GenericsArgsErrExtend; use crate::errors; use crate::hir_ty_lowering::{ - AssocItemQSelf, FeedConstTy, HirTyLowerer, OverlappingAsssocItemConstraints, PredicateFilter, - RegionInferReason, + AssocItemQSelf, FeedConstTy, GenericsArgsErrExtend, HirTyLowerer, ImpliedBoundsContext, + OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, }; #[derive(Debug, Default)] @@ -62,7 +60,7 @@ impl CollectedSizednessBounds { fn search_bounds_for<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>), ) { let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| { @@ -76,7 +74,7 @@ fn search_bounds_for<'tcx>( }; search_bounds(hir_bounds); - if let Some((self_ty, where_clause)) = self_ty_where_predicates { + if let ImpliedBoundsContext::TyParam(self_ty, where_clause) = context { for clause in where_clause { if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind && pred.is_param_bound(self_ty.to_def_id()) @@ -89,10 +87,10 @@ fn search_bounds_for<'tcx>( fn collect_relaxed_bounds<'tcx>( hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, ) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> { let mut relaxed_bounds: SmallVec<[_; 1]> = SmallVec::new(); - search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { + search_bounds_for(hir_bounds, context, |ptr| { if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) { relaxed_bounds.push(ptr); } @@ -102,11 +100,11 @@ fn collect_relaxed_bounds<'tcx>( fn collect_bounds<'a, 'tcx>( hir_bounds: &'a [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, target_did: DefId, ) -> CollectedBound { let mut collect_into = CollectedBound::default(); - search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| { + search_bounds_for(hir_bounds, context, |ptr| { if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) { return; } @@ -123,17 +121,17 @@ fn collect_bounds<'a, 'tcx>( fn collect_sizedness_bounds<'tcx>( tcx: TyCtxt<'tcx>, hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, span: Span, ) -> CollectedSizednessBounds { let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); - let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did); + let sized = collect_bounds(hir_bounds, context, sized_did); let meta_sized_did = tcx.require_lang_item(hir::LangItem::MetaSized, span); - let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did); + let meta_sized = collect_bounds(hir_bounds, context, meta_sized_did); let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); - let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did); + let pointee_sized = collect_bounds(hir_bounds, context, pointee_sized_did); CollectedSizednessBounds { sized, meta_sized, pointee_sized } } @@ -161,13 +159,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// bounds are present. /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if /// a `?Sized` bound is present. - pub(crate) fn add_sizedness_bounds( + pub(crate) fn add_implicit_sizedness_bounds( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &'tcx [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, - trait_did: Option, + context: ImpliedBoundsContext<'tcx>, span: Span, ) { let tcx = self.tcx(); @@ -181,33 +178,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let pointee_sized_did = tcx.require_lang_item(hir::LangItem::PointeeSized, span); // If adding sizedness bounds to a trait, then there are some relevant early exits - if let Some(trait_did) = trait_did { - let trait_did = trait_did.to_def_id(); - // Never add a default supertrait to `PointeeSized`. - if trait_did == pointee_sized_did { - return; + match context { + ImpliedBoundsContext::TraitDef(trait_did) => { + let trait_did = trait_did.to_def_id(); + // Never add a default supertrait to `PointeeSized`. + if trait_did == pointee_sized_did { + return; + } + // Don't add default sizedness supertraits to auto traits because it isn't possible to + // relax an automatically added supertrait on the defn itself. + if tcx.trait_is_auto(trait_did) { + return; + } } - // Don't add default sizedness supertraits to auto traits because it isn't possible to - // relax an automatically added supertrait on the defn itself. - if tcx.trait_is_auto(trait_did) { - return; + ImpliedBoundsContext::TyParam(..) | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { + // Report invalid relaxed bounds. + // FIXME: Since we only call this validation function here in this function, we only + // fully validate relaxed bounds in contexts where we perform + // "sized elaboration". In most cases that doesn't matter because we *usually* + // reject such relaxed bounds outright during AST lowering. + // However, this can easily get out of sync! Ideally, we would perform this step + // where we are guaranteed to catch *all* bounds like in + // `Self::lower_poly_trait_ref`. List of concrete issues: + // FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait + // bounds, trait alias bounds, assoc type bounds (ATB)! + let bounds = collect_relaxed_bounds(hir_bounds, context); + self.reject_duplicate_relaxed_bounds(bounds); } - } else { - // Report invalid relaxed bounds. - // FIXME: Since we only call this validation function here in this function, we only - // fully validate relaxed bounds in contexts where we perform - // "sized elaboration". In most cases that doesn't matter because we *usually* - // reject such relaxed bounds outright during AST lowering. - // However, this can easily get out of sync! Ideally, we would perform this step - // where we are guaranteed to catch *all* bounds like in - // `Self::lower_poly_trait_ref`. List of concrete issues: - // FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait - // bounds, trait alias bounds, assoc type bounds (ATB)! - let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates); - self.reject_duplicate_relaxed_bounds(bounds); } - let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span); + let collected = collect_sizedness_bounds(tcx, hir_bounds, context, span); if (collected.sized.maybe || collected.sized.negative) && !collected.sized.positive && !collected.meta_sized.any() @@ -217,62 +217,33 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // other explicit ones) - this can happen for trait aliases as well as bounds. add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); } else if !collected.any() { - if trait_did.is_some() { - // If there are no explicit sizedness bounds on a trait then add a default - // `MetaSized` supertrait. - add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); - } else { - // If there are no explicit sizedness bounds on a parameter then add a default - // `Sized` bound. - let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); - add_trait_bound(tcx, bounds, self_ty, sized_did, span); + match context { + ImpliedBoundsContext::TraitDef(..) => { + // If there are no explicit sizedness bounds on a trait then add a default + // `MetaSized` supertrait. + add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span); + } + ImpliedBoundsContext::TyParam(..) + | ImpliedBoundsContext::AssociatedTypeOrImplTrait => { + // If there are no explicit sizedness bounds on a parameter then add a default + // `Sized` bound. + let sized_did = tcx.require_lang_item(hir::LangItem::Sized, span); + add_trait_bound(tcx, bounds, self_ty, sized_did, span); + } } } } - /// Adds `experimental_default_bounds` bounds to the supertrait bounds. - pub(crate) fn add_default_super_traits( - &self, - trait_def_id: LocalDefId, - bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, - hir_bounds: &'tcx [hir::GenericBound<'tcx>], - hir_generics: &'tcx hir::Generics<'tcx>, - span: Span, - ) { - assert_matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias); - - // Supertraits for auto trait are unsound according to the unstable book: - // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits - if self.tcx().trait_is_auto(trait_def_id.to_def_id()) { - return; - } - - self.add_default_traits( - bounds, - self.tcx().types.self_param, - hir_bounds, - Some((trait_def_id, hir_generics.predicates)), - span, - ); - } - pub(crate) fn add_default_traits( &self, bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, span: Span, ) { self.tcx().default_traits().iter().for_each(|default_trait| { - self.add_default_trait( - *default_trait, - bounds, - self_ty, - hir_bounds, - self_ty_where_predicates, - span, - ); + self.add_default_trait(*default_trait, bounds, self_ty, hir_bounds, context, span); }); } @@ -285,15 +256,23 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { bounds: &mut Vec<(ty::Clause<'tcx>, Span)>, self_ty: Ty<'tcx>, hir_bounds: &[hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, span: Span, ) { let tcx = self.tcx(); - let trait_id = tcx.lang_items().get(trait_); - if let Some(trait_id) = trait_id - && self.should_add_default_traits(trait_id, hir_bounds, self_ty_where_predicates) + + // Supertraits for auto trait are unsound according to the unstable book: + // https://doc.rust-lang.org/beta/unstable-book/language-features/auto-traits.html#supertraits + if let ImpliedBoundsContext::TraitDef(trait_did) = context + && self.tcx().trait_is_auto(trait_did.into()) + { + return; + } + + if let Some(trait_did) = tcx.lang_items().get(trait_) + && self.should_add_default_traits(trait_did, hir_bounds, context) { - add_trait_bound(tcx, bounds, self_ty, trait_id, span); + add_trait_bound(tcx, bounds, self_ty, trait_did, span); } } @@ -302,9 +281,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, trait_def_id: DefId, hir_bounds: &'a [hir::GenericBound<'tcx>], - self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>, + context: ImpliedBoundsContext<'tcx>, ) -> bool { - let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id); + let collected = collect_bounds(hir_bounds, context, trait_def_id); !self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any() } 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 c0b1377308923..15d7da3a00707 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 @@ -4,9 +4,9 @@ use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, EmissionGuarantee, StashKey, Suggestions, struct_span_code_err, }; -use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, LangItem}; use rustc_lint_defs::builtin::{BARE_TRAIT_OBJECTS, UNUSED_ASSOCIATED_TYPE_BOUNDS}; use rustc_middle::ty::elaborate::ClauseWithSupertraitSpan; use rustc_middle::ty::{ @@ -24,7 +24,8 @@ use tracing::{debug, instrument}; use super::HirTyLowerer; use crate::errors::SelfInTypeAlias; use crate::hir_ty_lowering::{ - GenericArgCountMismatch, OverlappingAsssocItemConstraints, PredicateFilter, RegionInferReason, + GenericArgCountMismatch, ImpliedBoundsContext, OverlappingAsssocItemConstraints, + PredicateFilter, RegionInferReason, }; impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { @@ -76,12 +77,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .iter() .map(|&trait_ref| hir::GenericBound::Trait(trait_ref)) .collect::>(), - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, span, ); - let (elaborated_trait_bounds, elaborated_projection_bounds) = + let (mut elaborated_trait_bounds, elaborated_projection_bounds) = traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied()); + + // FIXME(sized-hierarchy): https://github.com/rust-lang/rust/pull/142712#issuecomment-3013231794 + debug!(?user_written_bounds, ?elaborated_trait_bounds); + let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span); + // Don't strip out `MetaSized` when the user wrote it explicitly, only when it was + // elaborated + if user_written_bounds + .iter() + .all(|(clause, _)| clause.as_trait_clause().map(|p| p.def_id()) != Some(meta_sized_did)) + { + elaborated_trait_bounds.retain(|(pred, _)| pred.def_id() != meta_sized_did); + } + debug!(?user_written_bounds, ?elaborated_trait_bounds); + let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = elaborated_trait_bounds .into_iter() .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 00f9095757806..82a931dcca2a0 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -56,6 +56,19 @@ use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_ use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; +/// The context in which an implied bound is being added to a item being lowered (i.e. a sizedness +/// trait or a default trait) +#[derive(Clone, Copy)] +pub(crate) enum ImpliedBoundsContext<'tcx> { + /// An implied bound is added to a trait definition (i.e. a new supertrait), used when adding + /// a default `MetaSized` supertrait + TraitDef(LocalDefId), + /// An implied bound is added to a type parameter + TyParam(LocalDefId, &'tcx [hir::WherePredicate<'tcx>]), + /// An implied bound being added in any other context + AssociatedTypeOrImplTrait, +} + /// A path segment that is semantically allowed to have generic arguments. #[derive(Debug)] pub struct GenericPathSegment(pub DefId, pub usize); @@ -2513,12 +2526,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { PredicateFilter::All, OverlappingAsssocItemConstraints::Allowed, ); - self.add_sizedness_bounds( + self.add_implicit_sizedness_bounds( &mut bounds, self_ty, hir_bounds, - None, - None, + ImpliedBoundsContext::AssociatedTypeOrImplTrait, hir_ty.span, ); self.register_trait_ascription_bounds(bounds, hir_ty.hir_id, hir_ty.span); diff --git a/tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs b/tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs new file mode 100644 index 0000000000000..48d17ac9a3af5 --- /dev/null +++ b/tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs @@ -0,0 +1,18 @@ +//@ check-pass +#![crate_type = "lib"] +#![feature(sized_hierarchy)] + +// Tests that a bound on an associated type projection, of a trait with a sizedness bound, will be +// elaborated. + +trait FalseDeref { + type Target: std::marker::PointeeSized; +} + +trait Bar {} + +fn foo() +where + T::Target: Bar, +{ +} diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs index d5bf152b7963b..b13f9d90081cd 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.rs +++ b/tests/ui/sized-hierarchy/default-supertrait.rs @@ -52,14 +52,11 @@ fn with_pointeesized_supertrait() { requires_pointeesized::(); } -// `T` won't inherit the `const MetaSized` implicit supertrait of `Bare`, so there is an error on -// the bound, which is expected. +// `T` inherits the `const MetaSized` implicit supertrait of `Bare`. fn with_bare_trait() { -//~^ ERROR the size for values of type `T` cannot be known requires_sized::(); //~^ ERROR the size for values of type `T` cannot be known requires_metasized::(); - //~^ ERROR the size for values of type `T` cannot be known requires_pointeesized::(); } diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr index 2a521dce8b6bb..35875163774d4 100644 --- a/tests/ui/sized-hierarchy/default-supertrait.stderr +++ b/tests/ui/sized-hierarchy/default-supertrait.stderr @@ -62,22 +62,6 @@ LL | trait NegPointeeSized: ?PointeeSized { } | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0277]: the size for values of type `T` cannot be known - --> $DIR/default-supertrait.rs:57:38 - | -LL | fn with_bare_trait() { - | ^^^^ doesn't have a known size - | -note: required by a bound in `Bare` - --> $DIR/default-supertrait.rs:27:1 - | -LL | trait Bare {} - | ^^^^^^^^^^^^^ required by this bound in `Bare` -help: consider further restricting type parameter `T` with unstable trait `MetaSized` - | -LL | fn with_bare_trait() { - | ++++++++++++++++++++++++ - error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/default-supertrait.rs:40:22 | @@ -123,11 +107,10 @@ LL | fn with_pointeesized_supertrait $DIR/default-supertrait.rs:59:22 + --> $DIR/default-supertrait.rs:57:22 | LL | fn with_bare_trait() { | - this type parameter needs to be `Sized` -LL | LL | requires_sized::(); | ^ doesn't have a size known at compile-time | @@ -137,22 +120,6 @@ note: required by a bound in `requires_sized` LL | fn requires_sized() {} | ^^^^^ required by this bound in `requires_sized` -error[E0277]: the size for values of type `T` cannot be known - --> $DIR/default-supertrait.rs:61:26 - | -LL | requires_metasized::(); - | ^ doesn't have a known size - | -note: required by a bound in `requires_metasized` - --> $DIR/default-supertrait.rs:30:26 - | -LL | fn requires_metasized() {} - | ^^^^^^^^^ required by this bound in `requires_metasized` -help: consider further restricting type parameter `T` with unstable trait `MetaSized` - | -LL | fn with_bare_trait() { - | ++++++++++++++++++++++++ - -error: aborting due to 15 previous errors +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/sized-hierarchy/elaboration-simple.rs b/tests/ui/sized-hierarchy/elaboration-simple.rs new file mode 100644 index 0000000000000..87e100166a298 --- /dev/null +++ b/tests/ui/sized-hierarchy/elaboration-simple.rs @@ -0,0 +1,13 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib +#![feature(sized_hierarchy)] + +// Test demonstrating that elaboration of sizedness bounds works in the simplest cases. + +trait Trait {} + +fn f() { + require_metasized::(); +} + +fn require_metasized() {} diff --git a/tests/ui/sized-hierarchy/trait-alias-elaboration.rs b/tests/ui/sized-hierarchy/trait-alias-elaboration.rs new file mode 100644 index 0000000000000..a5b4443ffddd3 --- /dev/null +++ b/tests/ui/sized-hierarchy/trait-alias-elaboration.rs @@ -0,0 +1,16 @@ +#![feature(sized_hierarchy, trait_alias)] +use std::marker::MetaSized; + +// Trait aliases also have implicit `MetaSized` bounds, like traits. These are filtered out during +// elaboration of trait aliases when lowering `dyn TraitAlias` - however, if the user explicitly +// wrote `MetaSized` in the `dyn Trait` then that should still be an error so as not to accidentally +// accept this going forwards. + +trait Qux = Clone; + +type Foo = dyn Qux + MetaSized; +//~^ ERROR: only auto traits can be used as additional traits in a trait object + +type Bar = dyn Qux; + +fn main() {} diff --git a/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr b/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr new file mode 100644 index 0000000000000..394aae6f8e32f --- /dev/null +++ b/tests/ui/sized-hierarchy/trait-alias-elaboration.stderr @@ -0,0 +1,17 @@ +error[E0225]: only auto traits can be used as additional traits in a trait object + --> $DIR/trait-alias-elaboration.rs:11:16 + | +LL | trait Qux = Clone; + | ------------------ additional non-auto trait +LL | +LL | type Foo = dyn Qux + MetaSized; + | ^^^ --------- first non-auto trait + | | + | second non-auto trait comes from this alias + | + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: MetaSized + MetaSized + Clone {}` + = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0225`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 8d8909625ffc8..d179c80596238 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -19,23 +19,6 @@ error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` LL | Self::Assoc: A, | ^^^^ -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: MetaSized` - --> $DIR/normalize-param-env-2.rs:24:22 - | -LL | Self::Assoc: A, - | ^^^^ - | -note: required by a bound in `A` - --> $DIR/normalize-param-env-2.rs:9:1 - | -LL | / trait A { -LL | | type Assoc; -LL | | -LL | | fn f() -... | -LL | | } - | |_^ required by this bound in `A` - error[E0275]: overflow evaluating the requirement `<() as A>::Assoc well-formed` --> $DIR/normalize-param-env-2.rs:24:22 | @@ -63,6 +46,6 @@ LL | where LL | Self::Assoc: A, | ^^^^ required by this bound in `A::f` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr index 9f7f74f94664b..f5fd9ce9864ce 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr @@ -4,20 +4,6 @@ error[E0275]: overflow evaluating the requirement `::Assoc: Trait` LL | ::Assoc: Trait, | ^^^^^ -error[E0275]: overflow evaluating the requirement `::Assoc: MetaSized` - --> $DIR/normalize-param-env-4.rs:19:26 - | -LL | ::Assoc: Trait, - | ^^^^^ - | -note: required by a bound in `Trait` - --> $DIR/normalize-param-env-4.rs:7:1 - | -LL | / trait Trait { -LL | | type Assoc; -LL | | } - | |_^ required by this bound in `Trait` - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0275`.