1
Fork 0

Move trait bound modifiers into hir::PolyTraitRef

This commit is contained in:
Michael Goulet 2024-10-13 09:16:03 -04:00
parent f6648f252a
commit 7500e09b8b
32 changed files with 102 additions and 100 deletions

View file

@ -1225,7 +1225,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx, itctx,
TraitBoundModifiers::NONE, TraitBoundModifiers::NONE,
); );
let bound = (bound, hir::TraitBoundModifier::None);
let bounds = this.arena.alloc_from_iter([bound]); let bounds = this.arena.alloc_from_iter([bound]);
let lifetime_bound = this.elided_dyn_bound(t.span); let lifetime_bound = this.elided_dyn_bound(t.span);
(bounds, lifetime_bound) (bounds, lifetime_bound)
@ -1328,8 +1327,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// const trait bounds in trait object types. // const trait bounds in trait object types.
GenericBound::Trait(ty, modifiers) => { GenericBound::Trait(ty, modifiers) => {
let trait_ref = this.lower_poly_trait_ref(ty, itctx, *modifiers); let trait_ref = this.lower_poly_trait_ref(ty, itctx, *modifiers);
let polarity = this.lower_trait_bound_modifiers(*modifiers); Some(trait_ref)
Some((trait_ref, polarity))
} }
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() { if lifetime_bound.is_none() {
@ -1958,21 +1956,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
span_ext: DUMMY_SP, span_ext: DUMMY_SP,
}); });
hir::GenericBound::Trait( hir::GenericBound::Trait(hir::PolyTraitRef {
hir::PolyTraitRef { bound_generic_params: &[],
bound_generic_params: &[], modifiers: hir::TraitBoundModifier::None,
trait_ref: hir::TraitRef { trait_ref: hir::TraitRef {
path: self.make_lang_item_path( path: self.make_lang_item_path(trait_lang_item, opaque_ty_span, Some(bound_args)),
trait_lang_item, hir_ref_id: self.next_id(),
opaque_ty_span,
Some(bound_args),
),
hir_ref_id: self.next_id(),
},
span: opaque_ty_span,
}, },
hir::TraitBoundModifier::None, span: opaque_ty_span,
) })
} }
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
@ -1982,10 +1974,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
itctx: ImplTraitContext, itctx: ImplTraitContext,
) -> hir::GenericBound<'hir> { ) -> hir::GenericBound<'hir> {
match tpb { match tpb {
GenericBound::Trait(p, modifiers) => hir::GenericBound::Trait( GenericBound::Trait(p, modifiers) => {
self.lower_poly_trait_ref(p, itctx, *modifiers), hir::GenericBound::Trait(self.lower_poly_trait_ref(p, itctx, *modifiers))
self.lower_trait_bound_modifiers(*modifiers), }
),
GenericBound::Outlives(lifetime) => { GenericBound::Outlives(lifetime) => {
hir::GenericBound::Outlives(self.lower_lifetime(lifetime)) hir::GenericBound::Outlives(self.lower_lifetime(lifetime))
} }
@ -2194,7 +2185,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let bound_generic_params = let bound_generic_params =
self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params); self.lower_lifetime_binder(p.trait_ref.ref_id, &p.bound_generic_params);
let trait_ref = self.lower_trait_ref(modifiers, &p.trait_ref, itctx); let trait_ref = self.lower_trait_ref(modifiers, &p.trait_ref, itctx);
hir::PolyTraitRef { bound_generic_params, trait_ref, span: self.lower_span(p.span) } let modifiers = self.lower_trait_bound_modifiers(modifiers);
hir::PolyTraitRef {
bound_generic_params,
modifiers,
trait_ref,
span: self.lower_span(p.span),
}
} }
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> { fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
@ -2634,10 +2631,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => {
let principal = hir::PolyTraitRef { let principal = hir::PolyTraitRef {
bound_generic_params: &[], bound_generic_params: &[],
modifiers: hir::TraitBoundModifier::None,
trait_ref: hir::TraitRef { path, hir_ref_id: hir_id }, trait_ref: hir::TraitRef { path, hir_ref_id: hir_id },
span: self.lower_span(span), span: self.lower_span(span),
}; };
let principal = (principal, hir::TraitBoundModifier::None);
// The original ID is taken by the `PolyTraitRef`, // The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one. // so the `Ty` itself needs a different one.

View file

@ -254,7 +254,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
debug!(?hrtb_bounds); debug!(?hrtb_bounds);
hrtb_bounds.iter().for_each(|bound| { hrtb_bounds.iter().for_each(|bound| {
let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }, _) = bound else { let Trait(PolyTraitRef { trait_ref, span: trait_span, .. }) = bound else {
return; return;
}; };
diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static); diag.span_note(*trait_span, fluent::borrowck_limitations_implies_static);
@ -277,7 +277,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
return; return;
}; };
bounds.iter().for_each(|bd| { bounds.iter().for_each(|bd| {
if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }, _) = bd if let Trait(PolyTraitRef { trait_ref: tr_ref, .. }) = bd
&& let Def(_, res_defid) = tr_ref.path.res && let Def(_, res_defid) = tr_ref.path.res
&& res_defid == trait_res_defid // trait id matches && res_defid == trait_res_defid // trait id matches
&& let TyKind::Path(Resolved(_, path)) = bounded_ty.kind && let TyKind::Path(Resolved(_, path)) = bounded_ty.kind

View file

@ -837,7 +837,7 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
hir_ty hir_ty
); );
}; };
if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref, _)], .. } = opaque_ty if let hir::OpaqueTy { bounds: [hir::GenericBound::Trait(trait_ref)], .. } = opaque_ty
&& let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(args) = segment.args && let Some(args) = segment.args
&& let [constraint] = args.constraints && let [constraint] = args.constraints

View file

@ -520,7 +520,7 @@ pub enum TraitBoundModifier {
#[derive(Clone, Copy, Debug, HashStable_Generic)] #[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum GenericBound<'hir> { pub enum GenericBound<'hir> {
Trait(PolyTraitRef<'hir>, TraitBoundModifier), Trait(PolyTraitRef<'hir>),
Outlives(&'hir Lifetime), Outlives(&'hir Lifetime),
Use(&'hir [PreciseCapturingArg<'hir>], Span), Use(&'hir [PreciseCapturingArg<'hir>], Span),
} }
@ -528,7 +528,7 @@ pub enum GenericBound<'hir> {
impl GenericBound<'_> { impl GenericBound<'_> {
pub fn trait_ref(&self) -> Option<&TraitRef<'_>> { pub fn trait_ref(&self) -> Option<&TraitRef<'_>> {
match self { match self {
GenericBound::Trait(data, _) => Some(&data.trait_ref), GenericBound::Trait(data) => Some(&data.trait_ref),
_ => None, _ => None,
} }
} }
@ -2874,11 +2874,7 @@ pub enum TyKind<'hir> {
OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]), OpaqueDef(&'hir OpaqueTy<'hir>, &'hir [GenericArg<'hir>]),
/// A trait object type `Bound1 + Bound2 + Bound3` /// A trait object type `Bound1 + Bound2 + Bound3`
/// where `Bound` is a trait or a lifetime. /// where `Bound` is a trait or a lifetime.
TraitObject( TraitObject(&'hir [PolyTraitRef<'hir>], &'hir Lifetime, TraitObjectSyntax),
&'hir [(PolyTraitRef<'hir>, TraitBoundModifier)],
&'hir Lifetime,
TraitObjectSyntax,
),
/// Unused for now. /// Unused for now.
Typeof(&'hir AnonConst), Typeof(&'hir AnonConst),
/// `TyKind::Infer` means the type should be inferred instead of it having been /// `TyKind::Infer` means the type should be inferred instead of it having been
@ -3182,6 +3178,11 @@ pub struct PolyTraitRef<'hir> {
/// The `'a` in `for<'a> Foo<&'a T>`. /// The `'a` in `for<'a> Foo<&'a T>`.
pub bound_generic_params: &'hir [GenericParam<'hir>], pub bound_generic_params: &'hir [GenericParam<'hir>],
/// The constness and polarity of the trait ref.
///
/// The `async` modifier is lowered directly into a different trait for now.
pub modifiers: TraitBoundModifier,
/// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`. /// The `Foo<&'a T>` in `for<'a> Foo<&'a T>`.
pub trait_ref: TraitRef<'hir>, pub trait_ref: TraitRef<'hir>,

View file

@ -905,7 +905,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul
try_visit!(visitor.visit_array_length(length)); try_visit!(visitor.visit_array_length(length));
} }
TyKind::TraitObject(bounds, ref lifetime, _syntax) => { TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
for (bound, _modifier) in bounds { for bound in bounds {
try_visit!(visitor.visit_poly_trait_ref(bound)); try_visit!(visitor.visit_poly_trait_ref(bound));
} }
try_visit!(visitor.visit_lifetime(lifetime)); try_visit!(visitor.visit_lifetime(lifetime));
@ -1160,7 +1160,7 @@ pub fn walk_param_bound<'v, V: Visitor<'v>>(
bound: &'v GenericBound<'v>, bound: &'v GenericBound<'v>,
) -> V::Result { ) -> V::Result {
match *bound { match *bound {
GenericBound::Trait(ref typ, _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Trait(ref typ) => visitor.visit_poly_trait_ref(typ),
GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
GenericBound::Use(args, _) => { GenericBound::Use(args, _) => {
walk_list!(visitor, visit_precise_capturing_arg, args); walk_list!(visitor, visit_precise_capturing_arg, args);

View file

@ -832,7 +832,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for GATArgsCollector<'tcx> {
fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool { fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
match ty.kind { match ty.kind {
hir::TyKind::TraitObject([(trait_ref, _)], ..) => match trait_ref.trait_ref.path.segments { hir::TyKind::TraitObject([trait_ref], ..) => match trait_ref.trait_ref.path.segments {
[s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()), [s] => s.res.opt_def_id() == Some(trait_def_id.to_def_id()),
_ => false, _ => false,
}, },

View file

@ -866,7 +866,7 @@ impl<'tcx> ItemCtxt<'tcx> {
#[instrument(level = "trace", skip(self))] #[instrument(level = "trace", skip(self))]
fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool { fn bound_defines_assoc_item(&self, b: &hir::GenericBound<'_>, assoc_name: Ident) -> bool {
match b { match b {
hir::GenericBound::Trait(poly_trait_ref, _) => { hir::GenericBound::Trait(poly_trait_ref) => {
let trait_ref = &poly_trait_ref.trait_ref; let trait_ref = &poly_trait_ref.trait_ref;
if let Some(trait_did) = trait_ref.trait_def_id() { if let Some(trait_did) = trait_ref.trait_def_id() {
self.tcx.trait_may_define_assoc_item(trait_did, assoc_name) self.tcx.trait_may_define_assoc_item(trait_did, assoc_name)

View file

@ -644,7 +644,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
debug!(?bounds, ?lifetime, "TraitObject"); debug!(?bounds, ?lifetime, "TraitObject");
let scope = Scope::TraitRefBoundary { s: self.scope }; let scope = Scope::TraitRefBoundary { s: self.scope };
self.with(scope, |this| { self.with(scope, |this| {
for (bound, _) in bounds { for bound in bounds {
this.visit_poly_trait_ref_inner( this.visit_poly_trait_ref_inner(
bound, bound,
NonLifetimeBinderAllowed::Deny("trait object types"), NonLifetimeBinderAllowed::Deny("trait object types"),
@ -1918,7 +1918,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
return None; return None;
} }
predicate.bounds.iter().find_map(|bound| { predicate.bounds.iter().find_map(|bound| {
let hir::GenericBound::Trait(trait_, _) = bound else { let hir::GenericBound::Trait(trait_) = bound else {
return None; return None;
}; };
BoundVarContext::supertrait_hrtb_vars( BoundVarContext::supertrait_hrtb_vars(

View file

@ -44,10 +44,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut unbounds: SmallVec<[_; 1]> = SmallVec::new(); let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| { let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
for hir_bound in hir_bounds { for hir_bound in hir_bounds {
let hir::GenericBound::Trait(ptr, modifier) = hir_bound else { let hir::GenericBound::Trait(ptr) = hir_bound else {
continue; continue;
}; };
match modifier { match ptr.modifiers {
hir::TraitBoundModifier::Maybe => unbounds.push(ptr), hir::TraitBoundModifier::Maybe => unbounds.push(ptr),
hir::TraitBoundModifier::Negative => { hir::TraitBoundModifier::Negative => {
if let Some(sized_def_id) = sized_def_id if let Some(sized_def_id) = sized_def_id
@ -156,8 +156,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
{ {
for hir_bound in hir_bounds { for hir_bound in hir_bounds {
match hir_bound { match hir_bound {
hir::GenericBound::Trait(poly_trait_ref, modifier) => { hir::GenericBound::Trait(poly_trait_ref) => {
let (constness, polarity) = match modifier { let (constness, polarity) = match poly_trait_ref.modifiers {
hir::TraitBoundModifier::Const => { hir::TraitBoundModifier::Const => {
(ty::BoundConstness::Const, ty::PredicatePolarity::Positive) (ty::BoundConstness::Const, ty::PredicatePolarity::Positive)
} }

View file

@ -30,7 +30,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self, &self,
span: Span, span: Span,
hir_id: hir::HirId, hir_id: hir::HirId,
hir_trait_bounds: &[(hir::PolyTraitRef<'tcx>, hir::TraitBoundModifier)], hir_trait_bounds: &[hir::PolyTraitRef<'tcx>],
lifetime: &hir::Lifetime, lifetime: &hir::Lifetime,
representation: DynKind, representation: DynKind,
) -> Ty<'tcx> { ) -> Ty<'tcx> {
@ -39,8 +39,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let mut bounds = Bounds::default(); let mut bounds = Bounds::default();
let mut potential_assoc_types = Vec::new(); let mut potential_assoc_types = Vec::new();
let dummy_self = self.tcx().types.trait_object_dummy_self; let dummy_self = self.tcx().types.trait_object_dummy_self;
for (trait_bound, modifier) in hir_trait_bounds.iter().rev() { for trait_bound in hir_trait_bounds.iter().rev() {
if *modifier == hir::TraitBoundModifier::Maybe { // FIXME: This doesn't handle `? const`.
if trait_bound.modifiers == hir::TraitBoundModifier::Maybe {
continue; continue;
} }
if let GenericArgCountResult { if let GenericArgCountResult {
@ -263,7 +264,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
let args = tcx.mk_args(&args); let args = tcx.mk_args(&args);
let span = i.bottom().1; let span = i.bottom().1;
let empty_generic_args = hir_trait_bounds.iter().any(|(hir_bound, _)| { let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| {
hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
&& hir_bound.span.contains(span) && hir_bound.span.contains(span)
}); });

View file

@ -718,7 +718,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
&self, &self,
associated_types: FxIndexMap<Span, FxIndexSet<DefId>>, associated_types: FxIndexMap<Span, FxIndexSet<DefId>>,
potential_assoc_types: Vec<usize>, potential_assoc_types: Vec<usize>,
trait_bounds: &[(hir::PolyTraitRef<'_>, hir::TraitBoundModifier)], trait_bounds: &[hir::PolyTraitRef<'_>],
) { ) {
if associated_types.values().all(|v| v.is_empty()) { if associated_types.values().all(|v| v.is_empty()) {
return; return;
@ -764,12 +764,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// related to issue #91997, turbofishes added only when in an expr or pat // related to issue #91997, turbofishes added only when in an expr or pat
let mut in_expr_or_pat = false; let mut in_expr_or_pat = false;
if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) { if let ([], [bound]) = (&potential_assoc_types[..], &trait_bounds) {
let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.0.trait_ref.hir_ref_id)); let grandparent = tcx.parent_hir_node(tcx.parent_hir_id(bound.trait_ref.hir_ref_id));
in_expr_or_pat = match grandparent { in_expr_or_pat = match grandparent {
hir::Node::Expr(_) | hir::Node::Pat(_) => true, hir::Node::Expr(_) | hir::Node::Pat(_) => true,
_ => false, _ => false,
}; };
match bound.0.trait_ref.path.segments { match bound.trait_ref.path.segments {
// FIXME: `trait_ref.path.span` can point to a full path with multiple // FIXME: `trait_ref.path.span` can point to a full path with multiple
// segments, even though `trait_ref.path.segments` is of length `1`. Work // segments, even though `trait_ref.path.segments` is of length `1`. Work
// around that bug here, even though it should be fixed elsewhere. // around that bug here, even though it should be fixed elsewhere.
@ -810,7 +810,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// and we can then use their span to indicate this to the user. // and we can then use their span to indicate this to the user.
let bound_names = trait_bounds let bound_names = trait_bounds
.iter() .iter()
.filter_map(|(poly_trait_ref, _)| { .filter_map(|poly_trait_ref| {
let path = poly_trait_ref.trait_ref.path.segments.last()?; let path = poly_trait_ref.trait_ref.path.segments.last()?;
let args = path.args?; let args = path.args?;

View file

@ -50,7 +50,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
.ok() .ok()
.is_some_and(|s| s.trim_end().ends_with('<')); .is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.0.trait_ref.path.is_global(); let is_global = poly_trait_ref.trait_ref.path.is_global();
let mut sugg = vec![( let mut sugg = vec![(
self_ty.span.shrink_to_lo(), self_ty.span.shrink_to_lo(),
@ -211,7 +211,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
// Check if trait object is safe for suggesting dynamic dispatch. // Check if trait object is safe for suggesting dynamic dispatch.
let is_dyn_compatible = match self_ty.kind { let is_dyn_compatible = match self_ty.kind {
hir::TyKind::TraitObject(objects, ..) => { hir::TyKind::TraitObject(objects, ..) => {
objects.iter().all(|(o, _)| match o.trait_ref.path.res { objects.iter().all(|o| match o.trait_ref.path.res {
Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id), Res::Def(DefKind::Trait, id) => tcx.is_dyn_compatible(id),
_ => false, _ => false,
}) })

View file

@ -301,16 +301,13 @@ impl<'a> State<'a> {
self.word_space("dyn"); self.word_space("dyn");
} }
let mut first = true; let mut first = true;
for (bound, modifier) in bounds { for bound in bounds {
if first { if first {
first = false; first = false;
} else { } else {
self.nbsp(); self.nbsp();
self.word_space("+"); self.word_space("+");
} }
if *modifier == TraitBoundModifier::Maybe {
self.word("?");
}
self.print_poly_trait_ref(bound); self.print_poly_trait_ref(bound);
} }
if !lifetime.is_elided() { if !lifetime.is_elided() {
@ -679,6 +676,10 @@ impl<'a> State<'a> {
} }
fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) { fn print_poly_trait_ref(&mut self, t: &hir::PolyTraitRef<'_>) {
// FIXME: This isn't correct!
if t.modifiers == TraitBoundModifier::Maybe {
self.word("?");
}
self.print_formal_generic_params(t.bound_generic_params); self.print_formal_generic_params(t.bound_generic_params);
self.print_trait_ref(&t.trait_ref); self.print_trait_ref(&t.trait_ref);
} }
@ -2077,10 +2078,7 @@ impl<'a> State<'a> {
} }
match bound { match bound {
GenericBound::Trait(tref, modifier) => { GenericBound::Trait(tref) => {
if modifier == &TraitBoundModifier::Maybe {
self.word("?");
}
self.print_poly_trait_ref(tref); self.print_poly_trait_ref(tref);
} }
GenericBound::Outlives(lt) => { GenericBound::Outlives(lt) => {

View file

@ -849,7 +849,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
hir::FnRetTy::Return(hir_ty) => { hir::FnRetTy::Return(hir_ty) => {
if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind if let hir::TyKind::OpaqueDef(op_ty, ..) = hir_ty.kind
// FIXME: account for RPITIT. // FIXME: account for RPITIT.
&& let [hir::GenericBound::Trait(trait_ref, _)] = op_ty.bounds && let [hir::GenericBound::Trait(trait_ref)] = op_ty.bounds
&& let Some(hir::PathSegment { args: Some(generic_args), .. }) = && let Some(hir::PathSegment { args: Some(generic_args), .. }) =
trait_ref.trait_ref.path.segments.last() trait_ref.trait_ref.path.segments.last()
&& let [constraint] = generic_args.constraints && let [constraint] = generic_args.constraints
@ -1035,7 +1035,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// extract all bounds from the source code using their spans // extract all bounds from the source code using their spans
let all_matching_bounds_strs = predicates_from_where let all_matching_bounds_strs = predicates_from_where
.filter_map(|bound| match bound { .filter_map(|bound| match bound {
GenericBound::Trait(_, _) => { GenericBound::Trait(_) => {
self.tcx.sess.source_map().span_to_snippet(bound.span()).ok() self.tcx.sess.source_map().span_to_snippet(bound.span()).ok()
} }
_ => None, _ => None,

View file

@ -112,10 +112,11 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) { fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return }; let hir::TyKind::TraitObject(bounds, _lifetime, _syntax) = &ty.kind else { return };
for (bound, modifier) in &bounds[..] { for bound in &bounds[..] {
let def_id = bound.trait_ref.trait_def_id(); let def_id = bound.trait_ref.trait_def_id();
if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop)) if def_id.is_some_and(|def_id| cx.tcx.is_lang_item(def_id, LangItem::Drop))
&& *modifier != hir::TraitBoundModifier::Maybe // FIXME: ?Drop is not a thing.
&& bound.modifiers != hir::TraitBoundModifier::Maybe
{ {
let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return }; let Some(def_id) = cx.tcx.get_diagnostic_item(sym::needs_drop) else { return };
cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id }); cx.emit_span_lint(DYN_DROP, bound.span, DropGlue { tcx: cx.tcx, def_id });

View file

@ -192,7 +192,8 @@ fn suggest_changing_unsized_bound(
.iter() .iter()
.enumerate() .enumerate()
.filter(|(_, bound)| { .filter(|(_, bound)| {
if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound if let hir::GenericBound::Trait(poly) = bound
&& poly.modifiers == hir::TraitBoundModifier::Maybe
&& poly.trait_ref.trait_def_id() == def_id && poly.trait_ref.trait_def_id() == def_id
{ {
true true

View file

@ -86,7 +86,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
} }
hir::TyKind::TraitObject(bounds, ..) => { hir::TyKind::TraitObject(bounds, ..) => {
for (bound, _) in bounds { for bound in bounds {
self.current_index.shift_in(1); self.current_index.shift_in(1);
self.visit_poly_trait_ref(bound); self.visit_poly_trait_ref(bound);
self.current_index.shift_out(1); self.current_index.shift_out(1);

View file

@ -599,7 +599,7 @@ impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
_, _,
) = t.kind ) = t.kind
{ {
for (ptr, _) in poly_trait_refs { for ptr in poly_trait_refs {
if Some(self.1) == ptr.trait_ref.trait_def_id() { if Some(self.1) == ptr.trait_ref.trait_def_id() {
self.0.push(ptr.span); self.0.push(ptr.span);
} }

View file

@ -894,7 +894,9 @@ fn foo(&self) -> Self::T { String::new() }
// FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting. // FIXME: we would want to call `resolve_vars_if_possible` on `ty` before suggesting.
let trait_bounds = bounds.iter().filter_map(|bound| match bound { let trait_bounds = bounds.iter().filter_map(|bound| match bound {
hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::None) => Some(ptr), hir::GenericBound::Trait(ptr) if ptr.modifiers == hir::TraitBoundModifier::None => {
Some(ptr)
}
_ => None, _ => None,
}); });

View file

@ -740,9 +740,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match ( ) if std::iter::zip(*last_bounds, *exp_bounds).all(|(left, right)| match (
left, right, left, right,
) { ) {
(hir::GenericBound::Trait(tl, ml), hir::GenericBound::Trait(tr, mr)) // FIXME: Suspicious
(hir::GenericBound::Trait(tl), hir::GenericBound::Trait(tr))
if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id() if tl.trait_ref.trait_def_id() == tr.trait_ref.trait_def_id()
&& ml == mr => && tl.modifiers == tr.modifiers =>
{ {
true true
} }

View file

@ -439,7 +439,7 @@ pub fn report_dyn_incompatibility<'tcx>(
if tcx.parent_hir_node(hir_id).fn_sig().is_some() { if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
// Do not suggest `impl Trait` when dealing with things like super-traits. // Do not suggest `impl Trait` when dealing with things like super-traits.
err.span_suggestion_verbose( err.span_suggestion_verbose(
ty.span.until(trait_ref.0.span), ty.span.until(trait_ref.span),
"consider using an opaque type instead", "consider using an opaque type instead",
"impl ", "impl ",
Applicability::MaybeIncorrect, Applicability::MaybeIncorrect,

View file

@ -3074,11 +3074,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
match ty.kind { match ty.kind {
hir::TyKind::TraitObject(traits, _, _) => { hir::TyKind::TraitObject(traits, _, _) => {
let (span, kw) = match traits { let (span, kw) = match traits {
[(first, _), ..] if first.span.lo() == ty.span.lo() => { [first, ..] if first.span.lo() == ty.span.lo() => {
// Missing `dyn` in front of trait object. // Missing `dyn` in front of trait object.
(ty.span.shrink_to_lo(), "dyn ") (ty.span.shrink_to_lo(), "dyn ")
} }
[(first, _), ..] => (ty.span.until(first.span), ""), [first, ..] => (ty.span.until(first.span), ""),
[] => span_bug!(ty.span, "trait object with no traits: {ty:?}"), [] => span_bug!(ty.span, "trait object with no traits: {ty:?}"),
}; };
let needs_parens = traits.len() != 1; let needs_parens = traits.len() != 1;
@ -5162,7 +5162,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span); let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span);
let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty(); let future = tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();
let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { let [hir::GenericBound::Trait(trait_ref)] = future.bounds else {
// `async fn` should always lower to a single bound... but don't ICE. // `async fn` should always lower to a single bound... but don't ICE.
return None; return None;
}; };

View file

@ -125,7 +125,7 @@ fn sized_trait_bound_spans<'tcx>(
bounds: hir::GenericBounds<'tcx>, bounds: hir::GenericBounds<'tcx>,
) -> impl 'tcx + Iterator<Item = Span> { ) -> impl 'tcx + Iterator<Item = Span> {
bounds.iter().filter_map(move |b| match b { bounds.iter().filter_map(move |b| match b {
hir::GenericBound::Trait(trait_ref, hir::TraitBoundModifier::None) hir::GenericBound::Trait(trait_ref)
if trait_has_sized_self( if trait_has_sized_self(
tcx, tcx,
trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()), trait_ref.trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),

View file

@ -214,15 +214,15 @@ fn clean_generic_bound<'tcx>(
) -> Option<GenericBound> { ) -> Option<GenericBound> {
Some(match *bound { Some(match *bound {
hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)), hir::GenericBound::Outlives(lt) => GenericBound::Outlives(clean_lifetime(lt, cx)),
hir::GenericBound::Trait(ref t, modifier) => { hir::GenericBound::Trait(ref t) => {
// `T: ~const Destruct` is hidden because `T: Destruct` is a no-op. // `T: ~const Destruct` is hidden because `T: Destruct` is a no-op.
if modifier == hir::TraitBoundModifier::MaybeConst if t.modifiers == hir::TraitBoundModifier::MaybeConst
&& cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap()) && cx.tcx.lang_items().destruct_trait() == Some(t.trait_ref.trait_def_id().unwrap())
{ {
return None; return None;
} }
GenericBound::TraitBound(clean_poly_trait_ref(t, cx), modifier) GenericBound::TraitBound(clean_poly_trait_ref(t, cx), t.modifiers)
} }
hir::GenericBound::Use(args, ..) => { hir::GenericBound::Use(args, ..) => {
GenericBound::Use(args.iter().map(|arg| arg.name()).collect()) GenericBound::Use(args.iter().map(|arg| arg.name()).collect())
@ -1833,7 +1833,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T
} }
TyKind::Path(_) => clean_qpath(ty, cx), TyKind::Path(_) => clean_qpath(ty, cx),
TyKind::TraitObject(bounds, lifetime, _) => { TyKind::TraitObject(bounds, lifetime, _) => {
let bounds = bounds.iter().map(|(bound, _)| clean_poly_trait_ref(bound, cx)).collect(); let bounds = bounds.iter().map(|bound| clean_poly_trait_ref(bound, cx)).collect();
let lifetime = let lifetime =
if !lifetime.is_elided() { Some(clean_lifetime(lifetime, cx)) } else { None }; if !lifetime.is_elided() { Some(clean_lifetime(lifetime, cx)) } else { None };
DynTrait(bounds, lifetime) DynTrait(bounds, lifetime)

View file

@ -242,7 +242,8 @@ fn collect_supertrait_bounds<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds
bounds bounds
.iter() .iter()
.filter_map(|bound| { .filter_map(|bound| {
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound if let GenericBound::Trait(poly_trait) = bound
&& let TraitBoundModifier::None = poly_trait.modifiers
&& let [.., path] = poly_trait.trait_ref.path.segments && let [.., path] = poly_trait.trait_ref.path.segments
&& poly_trait.bound_generic_params.is_empty() && poly_trait.bound_generic_params.is_empty()
&& let Some(trait_def_id) = path.res.opt_def_id() && let Some(trait_def_id) = path.res.opt_def_id()
@ -307,7 +308,8 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
// This involves some extra logic when generic arguments are present, since // This involves some extra logic when generic arguments are present, since
// simply comparing trait `DefId`s won't be enough. We also need to compare the generics. // simply comparing trait `DefId`s won't be enough. We also need to compare the generics.
for (index, bound) in bounds.iter().enumerate() { for (index, bound) in bounds.iter().enumerate() {
if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound if let GenericBound::Trait(poly_trait) = bound
&& let TraitBoundModifier::None = poly_trait.modifiers
&& let [.., path] = poly_trait.trait_ref.path.segments && let [.., path] = poly_trait.trait_ref.path.segments
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args) && let implied_args = path.args.map_or([].as_slice(), |a| a.args)
&& let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints) && let implied_constraints = path.args.map_or([].as_slice(), |a| a.constraints)

View file

@ -310,7 +310,7 @@ fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&
if let ty::Alias(_, alias_ty) = ty.kind() if let ty::Alias(_, alias_ty) = ty.kind()
&& let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id) && let Some(Node::OpaqueTy(opaque)) = cx.tcx.hir().get_if_local(alias_ty.def_id)
&& let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin && let OpaqueTyOrigin::AsyncFn { .. } = opaque.origin
&& let [GenericBound::Trait(trait_ref, _)] = &opaque.bounds && let [GenericBound::Trait(trait_ref)] = &opaque.bounds
&& let Some(segment) = trait_ref.trait_ref.path.segments.last() && let Some(segment) = trait_ref.trait_ref.path.segments.last()
&& let Some(generic_args) = segment.args && let Some(generic_args) = segment.args
&& let [constraint] = generic_args.constraints && let [constraint] = generic_args.constraints

View file

@ -163,7 +163,7 @@ fn check_fn_inner<'tcx>(
if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) { if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) {
return; return;
} }
if let GenericBound::Trait(ref trait_ref, _) = *bound { if let GenericBound::Trait(ref trait_ref) = *bound {
let params = &trait_ref let params = &trait_ref
.trait_ref .trait_ref
.path .path
@ -438,7 +438,7 @@ impl<'tcx> Visitor<'tcx> for RefVisitor<'_, 'tcx> {
if !lt.is_elided() { if !lt.is_elided() {
self.unelided_trait_object_lifetime = true; self.unelided_trait_object_lifetime = true;
} }
for (bound, _) in bounds { for bound in bounds {
self.visit_poly_trait_ref(bound); self.visit_poly_trait_ref(bound);
} }
}, },

View file

@ -107,7 +107,7 @@ fn future_trait_ref<'tcx>(
) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> { ) -> Option<(&'tcx TraitRef<'tcx>, Vec<LifetimeName>)> {
if let TyKind::OpaqueDef(opaque, bounds) = ty.kind if let TyKind::OpaqueDef(opaque, bounds) = ty.kind
&& let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| { && let Some(trait_ref) = opaque.bounds.iter().find_map(|bound| {
if let GenericBound::Trait(poly, _) = bound { if let GenericBound::Trait(poly) = bound {
Some(&poly.trait_ref) Some(&poly.trait_ref)
} else { } else {
None None

View file

@ -40,7 +40,6 @@ struct Bound<'tcx> {
ident: Ident, ident: Ident,
trait_bound: &'tcx PolyTraitRef<'tcx>, trait_bound: &'tcx PolyTraitRef<'tcx>,
modifier: TraitBoundModifier,
predicate_pos: usize, predicate_pos: usize,
bound_pos: usize, bound_pos: usize,
@ -65,11 +64,10 @@ fn type_param_bounds<'tcx>(generics: &'tcx Generics<'tcx>) -> impl Iterator<Item
.iter() .iter()
.enumerate() .enumerate()
.filter_map(move |(bound_pos, bound)| match bound { .filter_map(move |(bound_pos, bound)| match bound {
&GenericBound::Trait(ref trait_bound, modifier) => Some(Bound { &GenericBound::Trait(ref trait_bound) => Some(Bound {
param, param,
ident, ident,
trait_bound, trait_bound,
modifier,
predicate_pos, predicate_pos,
bound_pos, bound_pos,
}), }),
@ -120,13 +118,13 @@ impl LateLintPass<'_> for NeedlessMaybeSized {
let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics) let maybe_sized_params: DefIdMap<_> = type_param_bounds(generics)
.filter(|bound| { .filter(|bound| {
bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait) bound.trait_bound.trait_ref.trait_def_id() == Some(sized_trait)
&& bound.modifier == TraitBoundModifier::Maybe && bound.trait_bound.modifiers == TraitBoundModifier::Maybe
}) })
.map(|bound| (bound.param, bound)) .map(|bound| (bound.param, bound))
.collect(); .collect();
for bound in type_param_bounds(generics) { for bound in type_param_bounds(generics) {
if bound.modifier == TraitBoundModifier::None if bound.trait_bound.modifiers == TraitBoundModifier::None
&& let Some(sized_bound) = maybe_sized_params.get(&bound.param) && let Some(sized_bound) = maybe_sized_params.get(&bound.param)
&& let Some(path) = path_to_sized_bound(cx, bound.trait_bound) && let Some(path) = path_to_sized_bound(cx, bound.trait_bound)
{ {

View file

@ -182,7 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
// Iterate the bounds and add them to our seen hash // Iterate the bounds and add them to our seen hash
// If we haven't yet seen it, add it to the fixed traits // If we haven't yet seen it, add it to the fixed traits
for (bound, _) in bounds { for bound in bounds {
let Some(def_id) = bound.trait_ref.trait_def_id() else { let Some(def_id) = bound.trait_ref.trait_def_id() else {
continue; continue;
}; };
@ -197,9 +197,9 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
// If the number of unique traits isn't the same as the number of traits in the bounds, // If the number of unique traits isn't the same as the number of traits in the bounds,
// there must be 1 or more duplicates // there must be 1 or more duplicates
if bounds.len() != unique_traits.len() { if bounds.len() != unique_traits.len() {
let mut bounds_span = bounds[0].0.span; let mut bounds_span = bounds[0].span;
for (bound, _) in bounds.iter().skip(1) { for bound in bounds.iter().skip(1) {
bounds_span = bounds_span.to(bound.span); bounds_span = bounds_span.to(bound.span);
} }
@ -229,7 +229,8 @@ impl TraitBounds {
/// this MSRV? See <https://github.com/rust-lang/rust-clippy/issues/8772> for details. /// this MSRV? See <https://github.com/rust-lang/rust-clippy/issues/8772> for details.
fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool { fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool {
if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE) if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE)
&& let GenericBound::Trait(tr, TraitBoundModifier::Maybe) = bound && let GenericBound::Trait(tr) = bound
&& let TraitBoundModifier::Maybe = tr.modifiers
{ {
cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id() cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id()
} else { } else {
@ -375,11 +376,11 @@ impl Default for ComparableTraitRef {
} }
fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> { fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
if let GenericBound::Trait(t, tbm) = bound { if let GenericBound::Trait(t) = bound {
let trait_path = t.trait_ref.path; let trait_path = t.trait_ref.path;
let trait_span = { let trait_span = {
let path_span = trait_path.span; let path_span = trait_path.span;
if let TraitBoundModifier::Maybe = tbm { if let TraitBoundModifier::Maybe = t.modifiers {
path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?` path_span.with_lo(path_span.lo() - BytePos(1)) // include the `?`
} else { } else {
path_span path_span
@ -430,7 +431,7 @@ fn rollup_traits(
let mut repeated_res = false; let mut repeated_res = false;
let only_comparable_trait_refs = |bound: &GenericBound<'_>| { let only_comparable_trait_refs = |bound: &GenericBound<'_>| {
if let GenericBound::Trait(t, _) = bound { if let GenericBound::Trait(t) = bound {
Some((into_comparable_trait_ref(&t.trait_ref), t.span)) Some((into_comparable_trait_ref(&t.trait_ref), t.span))
} else { } else {
None None

View file

@ -82,7 +82,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
// Returns true if given type is `Any` trait. // Returns true if given type is `Any` trait.
fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool { fn is_any_trait(cx: &LateContext<'_>, t: &hir::Ty<'_>) -> bool {
if let TyKind::TraitObject(traits, ..) = t.kind { if let TyKind::TraitObject(traits, ..) = t.kind {
return traits.iter().any(|(bound, _)| { return traits.iter().any(|bound| {
if let Some(trait_did) = bound.trait_ref.trait_def_id() if let Some(trait_did) = bound.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Any, trait_did) && cx.tcx.is_diagnostic_item(sym::Any, trait_did)
{ {

View file

@ -55,7 +55,6 @@ impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
TyKind::TraitObject(param_bounds, _, _) => { TyKind::TraitObject(param_bounds, _, _) => {
let has_lifetime_parameters = param_bounds.iter().any(|bound| { let has_lifetime_parameters = param_bounds.iter().any(|bound| {
bound bound
.0
.bound_generic_params .bound_generic_params
.iter() .iter()
.any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. })) .any(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))