Auto merge of #142712 - davidtwco:sized-hierarchy-missing-default-bounds, r=lcnr
hir_analysis: add missing sizedness bounds Depends on rust-lang/rust#144064 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 - which is fixed by skipping `MetaSized` when elaborating trait aliases in lowering `dyn TraitAlias`.
This commit is contained in:
commit
f435972085
13 changed files with 215 additions and 194 deletions
|
|
@ -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,
|
||||
None,
|
||||
None,
|
||||
ImpliedBoundsContext::AssociatedTypeOrImplTrait,
|
||||
span,
|
||||
);
|
||||
icx.lowerer().add_default_traits(
|
||||
&mut bounds,
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
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,
|
||||
None,
|
||||
None,
|
||||
ImpliedBoundsContext::AssociatedTypeOrImplTrait,
|
||||
span,
|
||||
);
|
||||
icx.lowerer().add_default_traits(
|
||||
&mut bounds,
|
||||
item_ty,
|
||||
hir_bounds,
|
||||
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 => {}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
generics,
|
||||
ImpliedBoundsContext::TraitDef(trait_def_id),
|
||||
item.span,
|
||||
);
|
||||
icx.lowerer().add_default_traits(
|
||||
&mut bounds,
|
||||
self_param_ty,
|
||||
superbounds,
|
||||
ImpliedBoundsContext::TraitDef(trait_def_id),
|
||||
item.span,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<LocalDefId>,
|
||||
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())
|
||||
{
|
||||
add_trait_bound(tcx, bounds, self_ty, trait_id, span);
|
||||
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_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()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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::<Vec<_>>(),
|
||||
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()));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
18
tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs
Normal file
18
tests/ui/sized-hierarchy/bound-on-assoc-type-projection.rs
Normal file
|
|
@ -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<T: FalseDeref>()
|
||||
where
|
||||
T::Target: Bar,
|
||||
{
|
||||
}
|
||||
|
|
@ -52,14 +52,11 @@ fn with_pointeesized_supertrait<T: PointeeSized + PointeeSized_>() {
|
|||
requires_pointeesized::<T>();
|
||||
}
|
||||
|
||||
// `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<T: PointeeSized + Bare>() {
|
||||
//~^ ERROR the size for values of type `T` cannot be known
|
||||
requires_sized::<T>();
|
||||
//~^ ERROR the size for values of type `T` cannot be known
|
||||
requires_metasized::<T>();
|
||||
//~^ ERROR the size for values of type `T` cannot be known
|
||||
requires_pointeesized::<T>();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<T: PointeeSized + Bare>() {
|
||||
| ^^^^ 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<T: PointeeSized + Bare + std::marker::MetaSized>() {
|
||||
| ++++++++++++++++++++++++
|
||||
|
||||
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<T: PointeeSized + PointeeSized_ + std::mark
|
|||
| ++++++++++++++++++++++++
|
||||
|
||||
error[E0277]: the size for values of type `T` cannot be known at compilation time
|
||||
--> $DIR/default-supertrait.rs:59:22
|
||||
--> $DIR/default-supertrait.rs:57:22
|
||||
|
|
||||
LL | fn with_bare_trait<T: PointeeSized + Bare>() {
|
||||
| - this type parameter needs to be `Sized`
|
||||
LL |
|
||||
LL | requires_sized::<T>();
|
||||
| ^ 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<T: 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::<T>();
|
||||
| ^ doesn't have a known size
|
||||
|
|
||||
note: required by a bound in `requires_metasized`
|
||||
--> $DIR/default-supertrait.rs:30:26
|
||||
|
|
||||
LL | fn requires_metasized<T: MetaSized>() {}
|
||||
| ^^^^^^^^^ required by this bound in `requires_metasized`
|
||||
help: consider further restricting type parameter `T` with unstable trait `MetaSized`
|
||||
|
|
||||
LL | fn with_bare_trait<T: PointeeSized + Bare + std::marker::MetaSized>() {
|
||||
| ++++++++++++++++++++++++
|
||||
|
||||
error: aborting due to 15 previous errors
|
||||
error: aborting due to 13 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
|
|
|
|||
13
tests/ui/sized-hierarchy/elaboration-simple.rs
Normal file
13
tests/ui/sized-hierarchy/elaboration-simple.rs
Normal file
|
|
@ -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<T: Trait + std::marker::PointeeSized>() {
|
||||
require_metasized::<T>();
|
||||
}
|
||||
|
||||
fn require_metasized<T: std::marker::MetaSized>() {}
|
||||
16
tests/ui/sized-hierarchy/trait-alias-elaboration.rs
Normal file
16
tests/ui/sized-hierarchy/trait-alias-elaboration.rs
Normal file
|
|
@ -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() {}
|
||||
17
tests/ui/sized-hierarchy/trait-alias-elaboration.stderr
Normal file
17
tests/ui/sized-hierarchy/trait-alias-elaboration.stderr
Normal file
|
|
@ -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 <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0225`.
|
||||
|
|
@ -19,23 +19,6 @@ error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
|
|||
LL | Self::Assoc: A<T>,
|
||||
| ^^^^
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: MetaSized`
|
||||
--> $DIR/normalize-param-env-2.rs:24:22
|
||||
|
|
||||
LL | Self::Assoc: A<T>,
|
||||
| ^^^^
|
||||
|
|
||||
note: required by a bound in `A`
|
||||
--> $DIR/normalize-param-env-2.rs:9:1
|
||||
|
|
||||
LL | / trait A<T> {
|
||||
LL | | type Assoc;
|
||||
LL | |
|
||||
LL | | fn f()
|
||||
... |
|
||||
LL | | }
|
||||
| |_^ required by this bound in `A`
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc well-formed`
|
||||
--> $DIR/normalize-param-env-2.rs:24:22
|
||||
|
|
||||
|
|
@ -63,6 +46,6 @@ LL | where
|
|||
LL | Self::Assoc: A<T>,
|
||||
| ^^^^ 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`.
|
||||
|
|
|
|||
|
|
@ -4,20 +4,6 @@ error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: Trait`
|
|||
LL | <T as Trait>::Assoc: Trait,
|
||||
| ^^^^^
|
||||
|
||||
error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: MetaSized`
|
||||
--> $DIR/normalize-param-env-4.rs:19:26
|
||||
|
|
||||
LL | <T as Trait>::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`.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue