More robustly reject relaxing non-default trait bounds

This commit is contained in:
León Orell Valerian Liehr
2025-10-15 19:43:40 +02:00
parent aee9d3b4c0
commit 03dfb84ee1
12 changed files with 226 additions and 119 deletions

View File

@@ -204,7 +204,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// 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.check_and_report_invalid_relaxed_bounds(bounds);
self.reject_duplicate_relaxed_bounds(bounds);
}
let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
@@ -308,6 +308,53 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
!self.tcx().has_attr(CRATE_DEF_ID, sym::rustc_no_implicit_bounds) && !collected.any()
}
fn reject_duplicate_relaxed_bounds(&self, relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>) {
let tcx = self.tcx();
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
for bound in &relaxed_bounds {
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
}
}
for (trait_def_id, spans) in grouped_bounds {
if spans.len() > 1 {
let name = tcx.item_name(trait_def_id);
self.dcx()
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
.with_code(E0203)
.emit();
}
}
}
pub(crate) fn require_bound_to_relax_default_trait(
&self,
trait_ref: hir::TraitRef<'_>,
span: Span,
) {
let tcx = self.tcx();
if let Res::Def(DefKind::Trait, def_id) = trait_ref.path.res
&& (tcx.is_lang_item(def_id, hir::LangItem::Sized) || tcx.is_default_trait(def_id))
{
return;
}
self.dcx().span_err(
span,
if tcx.sess.opts.unstable_opts.experimental_default_bounds
|| tcx.features().more_maybe_bounds()
{
"bound modifier `?` can only be applied to default traits"
} else {
"bound modifier `?` can only be applied to `Sized`"
},
);
}
/// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
///
/// ### Examples

View File

@@ -8,7 +8,7 @@ use rustc_errors::{
};
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir, HirId, PolyTraitRef};
use rustc_hir::{self as hir, HirId};
use rustc_middle::bug;
use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -35,52 +35,6 @@ use crate::fluent_generated as fluent;
use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
/// Check for duplicate relaxed bounds and relaxed bounds of non-default traits.
pub(crate) fn check_and_report_invalid_relaxed_bounds(
&self,
relaxed_bounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
) {
let tcx = self.tcx();
let mut grouped_bounds = FxIndexMap::<_, Vec<_>>::default();
for bound in &relaxed_bounds {
if let Res::Def(DefKind::Trait, trait_def_id) = bound.trait_ref.path.res {
grouped_bounds.entry(trait_def_id).or_default().push(bound.span);
}
}
for (trait_def_id, spans) in grouped_bounds {
if spans.len() > 1 {
let name = tcx.item_name(trait_def_id);
self.dcx()
.struct_span_err(spans, format!("duplicate relaxed `{name}` bounds"))
.with_code(E0203)
.emit();
}
}
let sized_def_id = tcx.require_lang_item(hir::LangItem::Sized, DUMMY_SP);
for bound in relaxed_bounds {
if let Res::Def(DefKind::Trait, def_id) = bound.trait_ref.path.res
&& (def_id == sized_def_id || tcx.is_default_trait(def_id))
{
continue;
}
self.dcx().span_err(
bound.span,
if tcx.sess.opts.unstable_opts.experimental_default_bounds
|| tcx.features().more_maybe_bounds()
{
"bound modifier `?` can only be applied to default traits like `Sized`"
} else {
"bound modifier `?` can only be applied to `Sized`"
},
);
}
}
/// On missing type parameters, emit an E0393 error and provide a structured suggestion using
/// the type parameter's name as a placeholder.
pub(crate) fn report_missing_type_params(

View File

@@ -767,7 +767,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// We use the *resolved* bound vars later instead of the HIR ones since the former
// also include the bound vars of the overarching predicate if applicable.
let hir::PolyTraitRef { bound_generic_params: _, modifiers, ref trait_ref, span } =
let hir::PolyTraitRef { bound_generic_params: _, modifiers, trait_ref, span } =
*poly_trait_ref;
let hir::TraitBoundModifiers { constness, polarity } = modifiers;
@@ -791,6 +791,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
rustc_ast::BoundPolarity::Maybe(_) => {
self.require_bound_to_relax_default_trait(trait_ref, span);
(ty::PredicatePolarity::Positive, &mut Vec::new())
}
};