Guard us against degenerate default traits

This commit is contained in:
León Orell Valerian Liehr
2025-10-16 16:09:49 +02:00
parent 03dfb84ee1
commit 65814c80e8

View File

@@ -717,16 +717,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
trait_ref: &hir::TraitRef<'tcx>,
self_ty: Ty<'tcx>,
) -> ty::TraitRef<'tcx> {
let _ = self.prohibit_generic_args(
trait_ref.path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
let [leading_segments @ .., segment] = trait_ref.path.segments else { bug!() };
let _ = self.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
self.lower_mono_trait_ref(
trait_ref.path.span,
trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
self_ty,
trait_ref.path.segments.last().unwrap(),
segment,
true,
)
}
@@ -757,7 +756,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
#[instrument(level = "debug", skip(self, bounds))]
pub(crate) fn lower_poly_trait_ref(
&self,
poly_trait_ref: &hir::PolyTraitRef<'tcx>,
&hir::PolyTraitRef {
bound_generic_params,
modifiers: hir::TraitBoundModifiers { constness, polarity },
trait_ref,
span,
}: &hir::PolyTraitRef<'tcx>,
self_ty: Ty<'tcx>,
bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
predicate_filter: PredicateFilter,
@@ -767,52 +771,67 @@ 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, trait_ref, span } =
*poly_trait_ref;
let hir::TraitBoundModifiers { constness, polarity } = modifiers;
let _ = bound_generic_params;
let trait_def_id = trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise());
// Relaxed bounds `?Trait` and `PointeeSized` bounds aren't represented in the `middle::ty` IR
// Relaxed bounds `?Trait` and `PointeeSized` bounds aren't represented in the middle::ty IR
// as they denote the *absence* of a default bound. However, we can't bail out early here since
// we still need to perform several validation steps (see below). Instead, simply "pour" all
// resulting bounds "down the drain", i.e., into a new `Vec` that just gets dropped at the end.
let (polarity, bounds) = match polarity {
rustc_ast::BoundPolarity::Positive
if tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized) =>
{
let transient = match polarity {
hir::BoundPolarity::Positive => {
// To elaborate on the comment directly above, regarding `PointeeSized` specifically,
// we don't "reify" such bounds to avoid trait system limitations -- namely,
// non-global where-clauses being preferred over item bounds (where `PointeeSized`
// bounds would be proven) -- which can result in errors when a `PointeeSized`
// supertrait / bound / predicate is added to some items.
(ty::PredicatePolarity::Positive, &mut Vec::new())
tcx.is_lang_item(trait_def_id, hir::LangItem::PointeeSized)
}
rustc_ast::BoundPolarity::Positive => (ty::PredicatePolarity::Positive, bounds),
rustc_ast::BoundPolarity::Negative(_) => (ty::PredicatePolarity::Negative, bounds),
rustc_ast::BoundPolarity::Maybe(_) => {
hir::BoundPolarity::Negative(_) => false,
hir::BoundPolarity::Maybe(_) => {
self.require_bound_to_relax_default_trait(trait_ref, span);
(ty::PredicatePolarity::Positive, &mut Vec::new())
true
}
};
let bounds = if transient { &mut Vec::new() } else { bounds };
let trait_segment = trait_ref.path.segments.last().unwrap();
let polarity = match polarity {
hir::BoundPolarity::Positive | hir::BoundPolarity::Maybe(_) => {
ty::PredicatePolarity::Positive
}
hir::BoundPolarity::Negative(_) => ty::PredicatePolarity::Negative,
};
let _ = self.prohibit_generic_args(
trait_ref.path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.report_internal_fn_trait(span, trait_def_id, trait_segment, false);
let [leading_segments @ .., segment] = trait_ref.path.segments else { bug!() };
let _ = self.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
self.report_internal_fn_trait(span, trait_def_id, segment, false);
let (generic_args, arg_count) = self.lower_generic_args_of_path(
trait_ref.path.span,
trait_def_id,
&[],
trait_segment,
segment,
Some(self_ty),
);
let constraints = segment.args().constraints;
if transient && (!generic_args[1..].is_empty() || !constraints.is_empty()) {
// Since the bound won't be present in the middle::ty IR as established above, any
// arguments or constraints won't be checked for well-formedness in later passes.
//
// This is only an issue if the trait ref is otherwise valid which can only happen if
// the corresponding default trait has generic parameters or associated items. Such a
// trait would be degenerate. We delay a bug to detect and guard us against these.
//
// E.g: Given `/*default*/ trait Bound<'a: 'static, T, const N: usize> {}`,
// `?Bound<Vec<str>, { panic!() }>` won't be wfchecked.
self.dcx()
.span_delayed_bug(span, "transient bound should not have args or constraints");
}
let bound_vars = tcx.late_bound_vars(trait_ref.hir_ref_id);
debug!(?bound_vars);
@@ -924,7 +943,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
== OverlappingAsssocItemConstraints::Forbidden)
.then_some(FxIndexMap::default());
for constraint in trait_segment.args().constraints {
for constraint in constraints {
// Don't register any associated item constraints for negative bounds,
// since we should have emitted an error for them earlier, and they
// would not be well-formed!
@@ -1916,10 +1935,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
Res::Def(DefKind::OpaqueTy, did) => {
// Check for desugared `impl Trait`.
assert_matches!(tcx.opaque_ty_origin(did), hir::OpaqueTyOrigin::TyAlias { .. });
let item_segment = path.segments.split_last().unwrap();
let _ = self
.prohibit_generic_args(item_segment.1.iter(), GenericsArgsErrExtend::OpaqueTy);
let args = self.lower_generic_args_of_path_segment(span, did, item_segment.0);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self.prohibit_generic_args(
leading_segments.iter(),
GenericsArgsErrExtend::OpaqueTy,
);
let args = self.lower_generic_args_of_path_segment(span, did, segment);
Ty::new_opaque(tcx, did, args)
}
Res::Def(
@@ -1931,11 +1952,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
did,
) => {
assert_eq!(opt_self_ty, None);
let _ = self.prohibit_generic_args(
path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
self.lower_path_segment(span, did, path.segments.last().unwrap())
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
self.lower_path_segment(span, did, segment)
}
Res::Def(kind @ DefKind::Variant, def_id)
if let PermitVariants::Yes = permit_variants =>
@@ -1955,8 +1975,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
GenericsArgsErrExtend::DefVariant(&path.segments),
);
let GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
self.lower_path_segment(span, *def_id, &path.segments[*index])
let &GenericPathSegment(def_id, index) = generic_segments.last().unwrap();
self.lower_path_segment(span, def_id, &path.segments[index])
}
Res::Def(DefKind::TyParam, def_id) => {
assert_eq!(opt_self_ty, None);
@@ -2242,15 +2262,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
}
Res::Def(DefKind::Const | DefKind::Ctor(_, CtorKind::Const), did) => {
assert_eq!(opt_self_ty, None);
let _ = self.prohibit_generic_args(
path.segments.split_last().unwrap().1.iter(),
GenericsArgsErrExtend::None,
);
let args = self.lower_generic_args_of_path_segment(
span,
did,
path.segments.last().unwrap(),
);
let [leading_segments @ .., segment] = path.segments else { bug!() };
let _ = self
.prohibit_generic_args(leading_segments.iter(), GenericsArgsErrExtend::None);
let args = self.lower_generic_args_of_path_segment(span, did, segment);
ty::Const::new_unevaluated(tcx, ty::UnevaluatedConst::new(did, args))
}
Res::Def(DefKind::AssocConst, did) => {