More robustly reject relaxing non-default trait bounds
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user