Propagate TraitImplHeader to hir

This commit is contained in:
Cameron Steffen
2025-07-24 09:32:58 -05:00
parent 5bc23ce255
commit bf266dc834
59 changed files with 316 additions and 299 deletions
+46 -53
View File
@@ -360,75 +360,30 @@ fn lower_item_kind(
// lifetime to be added, but rather a reference to a
// parent lifetime.
let itctx = ImplTraitContext::Universal;
let (generics, (trait_ref, lowered_ty)) =
let (generics, (of_trait, lowered_ty)) =
self.lower_generics(ast_generics, id, itctx, |this| {
let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
};
let trait_ref = of_trait.as_ref().map(|of_trait| {
this.lower_trait_ref(
modifiers,
&of_trait.trait_ref,
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
)
});
let of_trait = of_trait
.as_deref()
.map(|of_trait| this.lower_trait_impl_header(of_trait));
let lowered_ty = this.lower_ty(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
);
(trait_ref, lowered_ty)
(of_trait, lowered_ty)
});
let new_impl_items = self
.arena
.alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
// to not cause an assertion failure inside the `lower_defaultness` function.
let has_val = true;
let (constness, safety, polarity, defaultness, defaultness_span) = match *of_trait {
Some(box TraitImplHeader {
constness,
safety,
polarity,
defaultness,
trait_ref: _,
}) => {
let constness = self.lower_constness(constness);
let safety = self.lower_safety(safety, hir::Safety::Safe);
let polarity = match polarity {
ImplPolarity::Positive => ImplPolarity::Positive,
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
};
let (defaultness, defaultness_span) =
self.lower_defaultness(defaultness, has_val);
(constness, safety, polarity, defaultness, defaultness_span)
}
None => (
hir::Constness::NotConst,
hir::Safety::Safe,
ImplPolarity::Positive,
hir::Defaultness::Final,
None,
),
};
hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
constness,
safety,
polarity,
defaultness,
defaultness_span,
hir::ItemKind::Impl(hir::Impl {
generics,
of_trait: trait_ref,
of_trait,
self_ty: lowered_ty,
items: new_impl_items,
}))
})
}
ItemKind::Trait(box Trait {
constness,
@@ -999,6 +954,44 @@ pub(crate) fn expr_err(&mut self, span: Span, guar: ErrorGuaranteed) -> hir::Exp
self.expr(span, hir::ExprKind::Err(guar))
}
fn lower_trait_impl_header(
&mut self,
trait_impl_header: &TraitImplHeader,
) -> &'hir hir::TraitImplHeader<'hir> {
let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } =
*trait_impl_header;
let constness = self.lower_constness(constness);
let safety = self.lower_safety(safety, hir::Safety::Safe);
let polarity = match polarity {
ImplPolarity::Positive => ImplPolarity::Positive,
ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
};
// `defaultness.has_value()` is never called for an `impl`, always `true` in order
// to not cause an assertion failure inside the `lower_defaultness` function.
let has_val = true;
let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
let modifiers = TraitBoundModifiers {
constness: BoundConstness::Never,
asyncness: BoundAsyncness::Normal,
// we don't use this in bound lowering
polarity: BoundPolarity::Positive,
};
let trait_ref = self.lower_trait_ref(
modifiers,
trait_ref,
ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
);
self.arena.alloc(hir::TraitImplHeader {
constness,
safety,
polarity,
defaultness,
defaultness_span,
trait_ref,
})
}
fn lower_impl_item(
&mut self,
i: &AssocItem,
+15 -12
View File
@@ -4194,7 +4194,7 @@ pub fn is_struct_or_union(&self) -> bool {
expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp;
}
}
@@ -4372,7 +4372,7 @@ pub enum ItemKind<'hir> {
TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
/// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
Impl(&'hir Impl<'hir>),
Impl(Impl<'hir>),
}
/// Represents an impl block declaration.
@@ -4381,6 +4381,14 @@ pub enum ItemKind<'hir> {
/// Refer to [`ImplItem`] for an associated item within an impl block.
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Impl<'hir> {
pub generics: &'hir Generics<'hir>,
pub of_trait: Option<&'hir TraitImplHeader<'hir>>,
pub self_ty: &'hir Ty<'hir>,
pub items: &'hir [ImplItemId],
}
#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct TraitImplHeader<'hir> {
pub constness: Constness,
pub safety: Safety,
pub polarity: ImplPolarity,
@@ -4388,13 +4396,7 @@ pub struct Impl<'hir> {
// We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
// decoding as `Span`s cannot be decoded when a `Session` is not available.
pub defaultness_span: Option<Span>,
pub generics: &'hir Generics<'hir>,
/// The trait being implemented, if any.
pub of_trait: Option<TraitRef<'hir>>,
pub self_ty: &'hir Ty<'hir>,
pub items: &'hir [ImplItemId],
pub trait_ref: TraitRef<'hir>,
}
impl ItemKind<'_> {
@@ -4756,8 +4758,8 @@ pub fn fn_decl(self) -> Option<&'hir FnDecl<'hir>> {
/// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`.
pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> {
if let Node::Item(Item { kind: ItemKind::Impl(impl_block), .. }) = self
&& let Some(trait_ref) = impl_block.of_trait
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(of_trait) = impl_block.of_trait
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
&& trait_id == trait_def_id
{
Some(impl_block)
@@ -4952,7 +4954,7 @@ mod size_asserts {
static_assert_size!(GenericArg<'_>, 16);
static_assert_size!(GenericBound<'_>, 64);
static_assert_size!(Generics<'_>, 56);
static_assert_size!(Impl<'_>, 80);
static_assert_size!(Impl<'_>, 40);
static_assert_size!(ImplItem<'_>, 96);
static_assert_size!(ImplItemKind<'_>, 40);
static_assert_size!(Item<'_>, 88);
@@ -4967,6 +4969,7 @@ mod size_asserts {
static_assert_size!(Res, 12);
static_assert_size!(Stmt<'_>, 32);
static_assert_size!(StmtKind<'_>, 16);
static_assert_size!(TraitImplHeader<'_>, 48);
static_assert_size!(TraitItem<'_>, 88);
static_assert_size!(TraitItemKind<'_>, 48);
static_assert_size!(Ty<'_>, 48);
+13 -13
View File
@@ -590,21 +590,21 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
try_visit!(visitor.visit_generics(generics));
try_visit!(visitor.visit_enum_def(enum_definition));
}
ItemKind::Impl(Impl {
constness: _,
safety: _,
defaultness: _,
polarity: _,
defaultness_span: _,
generics,
of_trait,
self_ty,
items,
}) => {
ItemKind::Impl(Impl { generics, of_trait, self_ty, items }) => {
try_visit!(visitor.visit_generics(generics));
visit_opt!(visitor, visit_trait_ref, of_trait);
if let Some(TraitImplHeader {
constness: _,
safety: _,
polarity: _,
defaultness: _,
defaultness_span: _,
trait_ref,
}) = of_trait
{
try_visit!(visitor.visit_trait_ref(trait_ref));
}
try_visit!(visitor.visit_ty_unambig(self_ty));
walk_list!(visitor, visit_impl_item_ref, *items);
walk_list!(visitor, visit_impl_item_ref, items);
}
ItemKind::Struct(ident, ref generics, ref struct_definition)
| ItemKind::Union(ident, ref generics, ref struct_definition) => {
@@ -244,48 +244,48 @@ pub(super) fn check_item<'tcx>(
//
// won't be allowed unless there's an *explicit* implementation of `Send`
// for `T`
hir::ItemKind::Impl(impl_) => {
let header = tcx.impl_trait_header(def_id);
let is_auto = header
.is_some_and(|header| tcx.trait_is_auto(header.trait_ref.skip_binder().def_id));
hir::ItemKind::Impl(ref impl_) => {
crate::impl_wf_check::check_impl_wf(tcx, def_id)?;
let mut res = Ok(());
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
res = Err(tcx
.dcx()
.struct_span_err(sp, "impls of auto traits cannot be default")
.with_span_labels(impl_.defaultness_span, "default because of this")
.with_span_label(sp, "auto trait")
.emit());
}
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
match header.map(|h| h.polarity) {
// `None` means this is an inherent impl
Some(ty::ImplPolarity::Positive) | None => {
res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
}
Some(ty::ImplPolarity::Negative) => {
let ast::ImplPolarity::Negative(span) = impl_.polarity else {
bug!("impl_polarity query disagrees with impl's polarity in HIR");
};
// FIXME(#27579): what amount of WF checking do we need for neg impls?
if let hir::Defaultness::Default { .. } = impl_.defaultness {
let mut spans = vec![span];
spans.extend(impl_.defaultness_span);
res = Err(struct_span_code_err!(
tcx.dcx(),
spans,
E0750,
"negative impls cannot be default impls"
)
if let Some(of_trait) = impl_.of_trait {
let header = tcx.impl_trait_header(def_id).unwrap();
let is_auto = tcx.trait_is_auto(header.trait_ref.skip_binder().def_id);
if let (hir::Defaultness::Default { .. }, true) = (of_trait.defaultness, is_auto) {
let sp = of_trait.trait_ref.path.span;
res = Err(tcx
.dcx()
.struct_span_err(sp, "impls of auto traits cannot be default")
.with_span_labels(of_trait.defaultness_span, "default because of this")
.with_span_label(sp, "auto trait")
.emit());
}
match header.polarity {
ty::ImplPolarity::Positive => {
res = res.and(check_impl(tcx, item, impl_));
}
ty::ImplPolarity::Negative => {
let ast::ImplPolarity::Negative(span) = of_trait.polarity else {
bug!("impl_polarity query disagrees with impl's polarity in HIR");
};
// FIXME(#27579): what amount of WF checking do we need for neg impls?
if let hir::Defaultness::Default { .. } = of_trait.defaultness {
let mut spans = vec![span];
spans.extend(of_trait.defaultness_span);
res = Err(struct_span_code_err!(
tcx.dcx(),
spans,
E0750,
"negative impls cannot be default impls"
)
.emit());
}
}
ty::ImplPolarity::Reservation => {
// FIXME: what amount of WF checking do we need for reservation impls?
}
}
Some(ty::ImplPolarity::Reservation) => {
// FIXME: what amount of WF checking do we need for reservation impls?
}
} else {
res = res.and(check_impl(tcx, item, impl_));
}
res
}
@@ -1258,16 +1258,15 @@ pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<()
})
}
#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
#[instrument(level = "debug", skip(tcx, impl_))]
fn check_impl<'tcx>(
tcx: TyCtxt<'tcx>,
item: &'tcx hir::Item<'tcx>,
hir_self_ty: &hir::Ty<'_>,
hir_trait_ref: &Option<hir::TraitRef<'_>>,
impl_: &hir::Impl<'_>,
) -> Result<(), ErrorGuaranteed> {
enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
match hir_trait_ref {
Some(hir_trait_ref) => {
match impl_.of_trait {
Some(of_trait) => {
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
@@ -1275,7 +1274,7 @@ fn check_impl<'tcx>(
// Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
// other `Foo` impls are incoherent.
tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
let trait_span = hir_trait_ref.path.span;
let trait_span = of_trait.trait_ref.path.span;
let trait_ref = wfcx.deeply_normalize(
trait_span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
@@ -1299,12 +1298,12 @@ fn check_impl<'tcx>(
if let Some(pred) = obligation.predicate.as_trait_clause()
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
{
obligation.cause.span = hir_self_ty.span;
obligation.cause.span = impl_.self_ty.span;
}
if let Some(pred) = obligation.predicate.as_projection_clause()
&& pred.skip_binder().self_ty() == trait_ref.self_ty()
{
obligation.cause.span = hir_self_ty.span;
obligation.cause.span = impl_.self_ty.span;
}
}
@@ -1321,7 +1320,7 @@ fn check_impl<'tcx>(
wfcx.register_obligation(Obligation::new(
tcx,
ObligationCause::new(
hir_self_ty.span,
impl_.self_ty.span,
wfcx.body_def_id,
ObligationCauseCode::WellFormed(None),
),
@@ -1342,7 +1341,7 @@ fn check_impl<'tcx>(
self_ty,
);
wfcx.register_wf_obligation(
hir_self_ty.span,
impl_.self_ty.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
self_ty.into(),
);
@@ -531,8 +531,10 @@ pub(crate) fn coerce_unsized_info<'tcx>(
}));
} else if diff_fields.len() > 1 {
let item = tcx.hir_expect_item(impl_did);
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
t.path.span
let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
&item.kind
{
of_trait.trait_ref.path.span
} else {
tcx.def_span(impl_did)
};
@@ -384,7 +384,7 @@ fn emit_orphan_check_error<'tcx>(
traits::OrphanCheckErr::NonLocalInputType(tys) => {
let item = tcx.hir_expect_item(impl_def_id);
let impl_ = item.expect_impl();
let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
let of_trait = impl_.of_trait.unwrap();
let span = tcx.def_span(impl_def_id);
let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
@@ -401,7 +401,7 @@ fn emit_orphan_check_error<'tcx>(
impl_.self_ty.span
} else {
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
hir_trait_ref.path.span
of_trait.trait_ref.path.span
};
ty = tcx.erase_regions(ty);
+16 -20
View File
@@ -1295,18 +1295,22 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
let icx = ItemCtxt::new(tcx, def_id);
let item = tcx.hir_expect_item(def_id);
let impl_ = item.expect_impl();
impl_.of_trait.as_ref().map(|ast_trait_ref| {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
if is_rustc_reservation && impl_.of_trait.is_none() {
tcx.dcx().span_err(item.span, "reservation impls can't be inherent");
}
impl_.of_trait.map(|of_trait| {
let selfty = tcx.type_of(def_id).instantiate_identity();
check_impl_constness(tcx, impl_.constness, ast_trait_ref);
check_impl_constness(tcx, of_trait.constness, &of_trait.trait_ref);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
let trait_ref = icx.lowerer().lower_impl_trait_ref(&of_trait.trait_ref, selfty);
ty::ImplTraitHeader {
trait_ref: ty::EarlyBinder::bind(trait_ref),
safety: impl_.safety,
polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
constness: impl_.constness,
safety: of_trait.safety,
polarity: polarity_of_impl(tcx, of_trait, is_rustc_reservation),
constness: of_trait.constness,
}
})
}
@@ -1350,26 +1354,18 @@ fn check_impl_constness(
fn polarity_of_impl(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
impl_: &hir::Impl<'_>,
span: Span,
of_trait: &hir::TraitImplHeader<'_>,
is_rustc_reservation: bool,
) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
match &impl_ {
hir::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => {
match of_trait.polarity {
hir::ImplPolarity::Negative(span) => {
if is_rustc_reservation {
let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
let span = span.to(of_trait.trait_ref.path.span);
tcx.dcx().span_err(span, "reservation impls can't be negative");
}
ty::ImplPolarity::Negative
}
hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => {
if is_rustc_reservation {
tcx.dcx().span_err(span, "reservation impls can't be inherent");
}
ty::ImplPolarity::Positive
}
hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: Some(_), .. } => {
hir::ImplPolarity::Positive => {
if is_rustc_reservation {
ty::ImplPolarity::Reservation
} else {
@@ -158,7 +158,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
if let Node::Item(item) = node {
match item.kind {
ItemKind::Impl(impl_) => {
if impl_.defaultness.is_default() {
if let Some(of_trait) = impl_.of_trait
&& of_trait.defaultness.is_default()
{
is_default_impl_trait = tcx
.impl_trait_ref(def_id)
.map(|t| ty::Binder::dummy(t.instantiate_identity()));
@@ -604,13 +604,10 @@ fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
#[instrument(level = "debug", skip(self))]
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
match &item.kind {
hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
if let Some(of_trait) = of_trait {
self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default());
}
}
_ => {}
if let hir::ItemKind::Impl(impl_) = item.kind
&& let Some(of_trait) = impl_.of_trait
{
self.record_late_bound_vars(of_trait.trait_ref.hir_ref_id, Vec::default());
}
match item.kind {
hir::ItemKind::Fn { generics, .. } => {
@@ -636,7 +633,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
| hir::ItemKind::Union(_, generics, _)
| hir::ItemKind::Trait(_, _, _, _, generics, ..)
| hir::ItemKind::TraitAlias(_, generics, ..)
| hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
| hir::ItemKind::Impl(hir::Impl { generics, .. }) => {
// These kinds of items have only early-bound lifetime parameters.
self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));
}
@@ -2106,7 +2103,7 @@ fn try_append_return_type_notation_params(
// If we have a self type alias (in an impl), try to resolve an
// associated item from one of the supertraits of the impl's trait.
Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => {
let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self
let hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = self
.tcx
.hir_node_by_def_id(impl_def_id.expect_local())
.expect_item()
@@ -2114,7 +2111,7 @@ fn try_append_return_type_notation_params(
else {
return;
};
let Some(trait_def_id) = trait_ref.trait_def_id() else {
let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
return;
};
let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars(
@@ -251,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
Ty::new_error(tcx, guar)
}
_ => icx.lower_ty(*self_ty),
_ => icx.lower_ty(self_ty),
},
ItemKind::Fn { .. } => {
let args = ty::GenericArgs::identity_for_item(tcx, def_id);
@@ -147,7 +147,11 @@ fn is_in_trait_impl(&self) -> bool {
let hir::Node::Item(hir::Item {
kind:
hir::ItemKind::Impl(hir::Impl {
of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
of_trait:
Some(hir::TraitImplHeader {
trait_ref: hir::TraitRef { hir_ref_id: id_in_of_trait, .. },
..
}),
..
}),
..
@@ -200,7 +200,7 @@ fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
}) = tcx.hir_node_by_def_id(parent_id)
&& self_ty.hir_id == impl_self_ty.hir_id
{
let Some(of_trait_ref) = of_trait else {
let Some(of_trait) = of_trait else {
diag.span_suggestion_verbose(
impl_self_ty.span.shrink_to_hi(),
"you might have intended to implement this trait for a given type",
@@ -209,10 +209,10 @@ fn maybe_suggest_blanket_trait_impl<G: EmissionGuarantee>(
);
return;
};
if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
let of_trait_span = of_trait.trait_ref.path.span;
// make sure that we are not calling unwrap to abort during the compilation
let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
return;
@@ -2732,7 +2732,7 @@ pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
};
let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl();
let trait_ref = self.lower_impl_trait_ref(i.of_trait.as_ref()?, self.lower_ty(i.self_ty));
let trait_ref = self.lower_impl_trait_ref(&i.of_trait?.trait_ref, self.lower_ty(i.self_ty));
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
tcx,
@@ -154,8 +154,9 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
hir::ItemKind::TyAlias(_, _, ty)
| hir::ItemKind::Static(_, _, ty, _)
| hir::ItemKind::Const(_, _, ty, _) => vec![ty],
hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
Some(t) => t
hir::ItemKind::Impl(impl_) => match impl_.of_trait {
Some(of_trait) => of_trait
.trait_ref
.path
.segments
.last()
+33 -28
View File
@@ -690,39 +690,44 @@ fn print_item(&mut self, item: &hir::Item<'_>) {
let (cb, ib) = self.head("union");
self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib);
}
hir::ItemKind::Impl(&hir::Impl {
constness,
safety,
polarity,
defaultness,
defaultness_span: _,
generics,
ref of_trait,
self_ty,
items,
}) => {
hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items }) => {
let (cb, ib) = self.head("");
self.print_defaultness(defaultness);
self.print_safety(safety);
self.word_nbsp("impl");
if let hir::Constness::Const = constness {
self.word_nbsp("const");
}
let impl_generics = |this: &mut Self| {
this.word_nbsp("impl");
if !generics.params.is_empty() {
this.print_generic_params(generics.params);
this.space();
}
};
if !generics.params.is_empty() {
self.print_generic_params(generics.params);
self.space();
}
match of_trait {
None => impl_generics(self),
Some(&hir::TraitImplHeader {
constness,
safety,
polarity,
defaultness,
defaultness_span: _,
ref trait_ref,
}) => {
self.print_defaultness(defaultness);
self.print_safety(safety);
if let hir::ImplPolarity::Negative(_) = polarity {
self.word("!");
}
impl_generics(self);
if let Some(t) = of_trait {
self.print_trait_ref(t);
self.space();
self.word_space("for");
if let hir::Constness::Const = constness {
self.word_nbsp("const");
}
if let hir::ImplPolarity::Negative(_) = polarity {
self.word("!");
}
self.print_trait_ref(trait_ref);
self.space();
self.word_space("for");
}
}
self.print_type(self_ty);
@@ -936,7 +936,7 @@ fn can_add_return_type(&self, fn_id: LocalDefId) -> bool {
Node::ImplItem(item) => {
// If it doesn't impl a trait, we can add a return type
let Node::Item(&hir::Item {
kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }),
kind: hir::ItemKind::Impl(hir::Impl { of_trait, .. }),
..
}) = self.tcx.parent_hir_node(item.hir_id())
else {
@@ -1103,7 +1103,7 @@ fn report_no_match_method_error(
self_ty.span.ctxt().outer_expn_data().kind,
ExpnKind::Macro(MacroKind::Derive, _)
) || matches!(
of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
Some(ExpnKind::Macro(MacroKind::Derive, _))
) =>
{
@@ -1165,13 +1165,13 @@ fn report_no_match_method_error(
entry.0.insert(cause_span);
entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
} else {
if let Some(trait_ref) = of_trait {
entry.0.insert(trait_ref.path.span);
if let Some(of_trait) = of_trait {
entry.0.insert(of_trait.trait_ref.path.span);
}
entry.0.insert(self_ty.span);
};
if let Some(trait_ref) = of_trait {
entry.1.insert((trait_ref.path.span, ""));
if let Some(of_trait) = of_trait {
entry.1.insert((of_trait.trait_ref.path.span, ""));
}
entry.1.insert((self_ty.span, ""));
}
@@ -61,8 +61,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
// `Deref` is being implemented for `t`
if let hir::ItemKind::Impl(impl_) = item.kind
// the trait is a `Deref` implementation
&& let Some(trait_) = &impl_.of_trait
&& let Some(did) = trait_.trait_def_id()
&& let Some(of_trait) = &impl_.of_trait
&& let Some(did) = of_trait.trait_ref.trait_def_id()
&& tcx.is_lang_item(did, LangItem::Deref)
// the self type is `dyn t_principal`
&& let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
+2 -2
View File
@@ -582,8 +582,8 @@ fn diagnostic_outside_of_impl<'cx>(
for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) {
debug!(?parent);
if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent
&& let hir::Impl { of_trait: Some(of_trait), .. } = impl_
&& let Some(def_id) = of_trait.trait_def_id()
&& let Some(of_trait) = impl_.of_trait
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(def_id)
&& matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
{
+2 -2
View File
@@ -129,8 +129,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// of the `impl` definition
let mut collector = PathCollector { paths: Vec::new() };
collector.visit_ty_unambig(&impl_.self_ty);
if let Some(of_trait) = &impl_.of_trait {
collector.visit_trait_ref(of_trait);
if let Some(of_trait) = impl_.of_trait {
collector.visit_trait_ref(&of_trait.trait_ref);
}
// 1.5. Remove any path that doesn't resolve to a `DefId` or if it resolve to a
+3 -4
View File
@@ -1155,8 +1155,7 @@ fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) {
let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
|| if let Some(&[hir::GenericArg::Type(ty)]) = i
.of_trait
.as_ref()
.and_then(|trait_ref| trait_ref.path.segments.last())
.and_then(|of_trait| of_trait.trait_ref.path.segments.last())
.map(|last_segment| last_segment.args().args)
{
matches!(&ty.kind, hir::TyKind::Tup([_]))
@@ -1646,8 +1645,8 @@ fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) {
&& let parent_hir_id = self.tcx.parent_hir_id(hir_id)
&& let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
&& let hir::ItemKind::Impl(impl_) = item.kind
&& let Some(trait_) = impl_.of_trait
&& let Some(def_id) = trait_.trait_def_id()
&& let Some(of_trait) = impl_.of_trait
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
&& self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
{
return;
+13 -11
View File
@@ -590,9 +590,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
// For implementations of traits, check the stability of each item
// individually as it's possible to have a stable trait with unstable
// items.
hir::ItemKind::Impl(hir::Impl {
of_trait: Some(t), self_ty, items, constness, ..
}) => {
hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), self_ty, items, .. }) => {
let features = self.tcx.features();
if features.staged_api() {
let attrs = self.tcx.hir_attrs(item.hir_id());
@@ -628,7 +626,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
{
let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
c.visit_ty_unambig(self_ty);
c.visit_trait_ref(t);
c.visit_trait_ref(&of_trait.trait_ref);
// Skip the lint if the impl is marked as unstable using
// #[unstable_feature_bound(..)]
@@ -641,7 +639,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
// do not lint when the trait isn't resolved, since resolution error should
// be fixed first
if t.path.res != Res::Err
if of_trait.trait_ref.path.res != Res::Err
&& c.fully_stable
&& !unstable_feature_bound_in_effect
{
@@ -655,7 +653,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
}
if features.const_trait_impl()
&& let hir::Constness::Const = constness
&& let hir::Constness::Const = of_trait.constness
{
let stable_or_implied_stable = match const_stab {
None => true,
@@ -671,7 +669,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
Some(_) => false,
};
if let Some(trait_id) = t.trait_def_id()
if let Some(trait_id) = of_trait.trait_ref.trait_def_id()
&& let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
{
// the const stability of a trait impl must match the const stability on the trait.
@@ -699,14 +697,18 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
}
}
if let hir::Constness::Const = constness
&& let Some(def_id) = t.trait_def_id()
if let hir::Constness::Const = of_trait.constness
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
{
// FIXME(const_trait_impl): Improve the span here.
self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
self.tcx.check_const_stability(
def_id,
of_trait.trait_ref.path.span,
of_trait.trait_ref.path.span,
);
}
for impl_item_ref in *items {
for impl_item_ref in items {
let impl_item = self.tcx.associated_item(impl_item_ref.owner_id);
if let Some(def_id) = impl_item.trait_item_def_id {
+2 -1
View File
@@ -1779,7 +1779,8 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
let trait_ref = trait_ref.instantiate_identity();
visitor.span = tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().path.span;
visitor.span =
tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span;
let _ =
visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
}
@@ -3471,8 +3471,8 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
..
})) => {
let mut spans = Vec::with_capacity(2);
if let Some(trait_ref) = of_trait {
spans.push(trait_ref.path.span);
if let Some(of_trait) = of_trait {
spans.push(of_trait.trait_ref.path.span);
}
spans.push(self_ty.span);
let mut spans: MultiSpan = spans.into();
@@ -3480,7 +3480,7 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
self_ty.span.ctxt().outer_expn_data().kind,
ExpnKind::Macro(MacroKind::Derive, _)
) || matches!(
of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
Some(ExpnKind::Macro(MacroKind::Derive, _))
) {
spans.push_span_label(
@@ -3592,7 +3592,7 @@ pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>(
..
})) => {
let mut spans = vec![self_ty.span];
spans.extend(of_trait.as_ref().map(|t| t.path.span));
spans.extend(of_trait.map(|t| t.trait_ref.path.span));
let mut spans: MultiSpan = spans.into();
spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
err.span_note(spans, msg);
+2 -2
View File
@@ -174,10 +174,10 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
})
.collect(),
ItemKind::Impl(impl_) => {
let Some(trait_ref) = impl_.of_trait else {
let Some(of_trait) = impl_.of_trait else {
return Default::default();
};
let Some(trait_def_id) = trait_ref.trait_def_id() else {
let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
return Default::default();
};
let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
@@ -172,10 +172,12 @@ fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span>
let trait_args = impl_
.of_trait
.into_iter()
.flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
.flat_map(|of_trait| of_trait.trait_ref.path.segments.last().unwrap().args().args)
.map(|arg| arg.span());
let dummy_spans_for_default_args =
impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
let dummy_spans_for_default_args = impl_
.of_trait
.into_iter()
.flat_map(|of_trait| iter::repeat(of_trait.trait_ref.path.span));
iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
} else {
bug!("unexpected item for impl {def_id:?}: {item:?}")
+1 -1
View File
@@ -87,7 +87,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {}
DefKind::Impl { of_trait } => {
if of_trait {
let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span;
let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
try_visit!(visitor.visit(span, args));
}
+5 -1
View File
@@ -81,7 +81,11 @@ fn sizedness_constraint_for_ty<'tcx>(
fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { defaultness, of_trait: Some(_), .. }),
kind:
hir::ItemKind::Impl(hir::Impl {
of_trait: Some(hir::TraitImplHeader { defaultness, .. }),
..
}),
..
})
| hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
+6 -3
View File
@@ -2768,7 +2768,7 @@ fn get_name(
// These kinds of item either don't need a `name` or accept a `None` one so we handle them
// before.
match item.kind {
ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
ItemKind::Use(path, kind) => {
return clean_use_statement(
item,
@@ -2896,7 +2896,7 @@ fn clean_impl<'tcx>(
) -> Vec<Item> {
let tcx = cx.tcx;
let mut ret = Vec::new();
let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
let trait_ = impl_.of_trait.map(|t| clean_trait_ref(&t.trait_ref, cx));
let items = impl_
.items
.iter()
@@ -2922,7 +2922,10 @@ fn clean_impl<'tcx>(
});
let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
let kind = ImplItem(Box::new(Impl {
safety: impl_.safety,
safety: match impl_.of_trait {
Some(of_trait) => of_trait.safety,
None => hir::Safety::Safe,
},
generics: clean_generics(impl_.generics, cx),
trait_,
for_,
@@ -534,6 +534,7 @@ fn get_item_name(item: &Item<'_>) -> Option<String> {
if let Some(of_trait) = im.of_trait {
let mut trait_segs: Vec<String> = of_trait
.trait_ref
.path
.segments
.iter()
@@ -37,12 +37,12 @@
impl<'tcx> LateLintPass<'tcx> for CopyIterator {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = item.kind
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& is_copy(cx, ty)
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Iterator, trait_id)
{
span_lint_and_note(
@@ -183,14 +183,14 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items: [child],
self_ty,
..
}) = item.kind
&& !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& !item.span.from_expansion()
&& let Some(def_id) = trait_ref.trait_def_id()
&& let Some(def_id) = of_trait.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Default, def_id)
&& let impl_item_hir = child.hir_id()
&& let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
+2 -1
View File
@@ -201,10 +201,11 @@
impl<'tcx> LateLintPass<'tcx> for Derive {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = item.kind
{
let trait_ref = &of_trait.trait_ref;
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
@@ -36,11 +36,11 @@
impl LateLintPass<'_> for EmptyDrop {
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items: [child],
..
}) = item.kind
&& trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
&& of_trait.trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
&& let impl_item_hir = child.hir_id()
&& let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
&& let ImplItemKind::Fn(_, b) = &impl_item.kind
@@ -52,7 +52,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
);
},
ItemKind::Impl(imp)
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id())
&& let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
&& error_def_id == trait_def_id
&& let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
@@ -254,10 +254,10 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio
if impl_item.ident.name == sym::fmt
&& let ImplItemKind::Fn(_, body_id) = impl_item.kind
&& let Some(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = get_parent_as_impl(cx.tcx, impl_item.hir_id())
&& let Some(did) = trait_ref.trait_def_id()
&& let Some(did) = of_trait.trait_ref.trait_def_id()
&& let Some(name) = cx.tcx.get_diagnostic_name(did)
&& matches!(name, sym::Debug | sym::Display)
{
@@ -67,12 +67,12 @@ pub fn new(conf: &'static Conf) -> Self {
impl<'tcx> LateLintPass<'tcx> for FromOverInto {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(hir_trait_ref),
of_trait: Some(of_trait),
self_ty,
items: [impl_item_ref],
..
}) = item.kind
&& let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
&& let Some(into_trait_seg) = of_trait.trait_ref.path.segments.last()
// `impl Into<target_ty> for self_ty`
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
&& span_is_local(item.span)
@@ -54,8 +54,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
if let ImplItemKind::Fn(_, body_id) = impl_item.kind
&& let hir::Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
&& let hir::ItemKind::Impl(impl_) = item.kind
&& let hir::Impl { of_trait, .. } = *impl_
&& of_trait.is_none()
&& let hir::Impl { of_trait: None, .. } = impl_
&& let body = cx.tcx.hir_body(body_id)
&& cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
&& !is_in_test(cx.tcx, impl_item.hir_id())
@@ -15,11 +15,11 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
&& let parent_node = cx.tcx.parent_hir_node(item.hir_id())
&& let Node::Item(parent_item) = parent_node
&& let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = &parent_item.kind
&& let Some(did) = trait_item_def_id_of_impl(cx, item.owner_id)
&& !is_from_ignored_trait(trait_ref, ignored_traits)
&& !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits)
{
let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id);
let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied();
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Item, ItemKind, Path, TraitRef};
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::declare_lint_pass;
@@ -76,10 +76,10 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes {
/// three of `Hash`, `Borrow<str>` and `Borrow<[u8]>`.
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Impl(imp) = item.kind
&& let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait
&& let Some(of_trait) = imp.of_trait
&& let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
&& let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash)
&& Res::Def(DefKind::Trait, hash_id) == *res
&& Res::Def(DefKind::Trait, hash_id) == of_trait.trait_ref.path.res
&& let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow)
// since we are in the `Hash` impl, we don't need to check for that.
// we need only to check for `Borrow<str>` and `Borrow<[u8]>`
@@ -89,7 +89,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
span_lint_and_then(
cx,
IMPL_HASH_BORROW_WITH_STR_AND_BYTES,
*span,
of_trait.trait_ref.path.span,
"the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented",
|diag| {
diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T>");
@@ -45,8 +45,8 @@
impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
let ItemKind::Impl(imp) = item.kind else { return };
let Some(r#trait) = imp.of_trait else { return };
let Some(trait_def_id) = r#trait.trait_def_id() else {
let Some(of_trait) = imp.of_trait else { return };
let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
return;
};
if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) {
@@ -125,8 +125,9 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
if let ItemKind::Impl(imp) = item.kind
&& let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
&& let Some(trait_ref) = imp.of_trait
&& trait_ref
&& let Some(of_trait) = imp.of_trait
&& of_trait
.trait_ref
.trait_def_id()
.is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
&& !item.span.in_external_macro(cx.sess().source_map())
@@ -150,7 +150,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
} = item.kind
{
check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv);
} else if let ItemKind::Impl(impl_) = item.kind
} else if let ItemKind::Impl(impl_) = &item.kind
&& !item.span.from_expansion()
{
report_extra_impl_lifetimes(cx, impl_);
@@ -712,8 +712,8 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, impl_.generics);
walk_generics(&mut checker, impl_.generics);
if let Some(ref trait_ref) = impl_.of_trait {
walk_trait_ref(&mut checker, trait_ref);
if let Some(of_trait) = impl_.of_trait {
walk_trait_ref(&mut checker, &of_trait.trait_ref);
}
walk_unambig_ty(&mut checker, impl_.self_ty);
for &item in impl_.items {
@@ -198,8 +198,8 @@ fn check_struct<'tcx>(
impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// is this an `impl Debug for X` block?
if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, .. }) = item.kind
&& let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res
if let ItemKind::Impl(Impl { of_trait: Some(of_trait), self_ty, .. }) = item.kind
&& let Res::Def(DefKind::Trait, trait_def_id) = of_trait.trait_ref.path.res
&& let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind
// make sure that the self type is either a struct, an enum or a union
// this prevents ICEs such as when self is a type parameter or a primitive type
@@ -61,10 +61,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
&& span_is_local(item.span)
&& let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
{
let trait_item_ids: DefIdSet = cx
.tcx
@@ -778,7 +778,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id())
&& let ItemKind::Impl(impl_block) = parent_item.kind
&& let Some(of_trait) = impl_block.of_trait
&& let Some(trait_id) = of_trait.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
{
// Replace all instances of `<Self as Trait>::AssocType` with the
// unit type and check again. If the result is the same then the
@@ -83,10 +83,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if !item.span.in_external_macro(cx.tcx.sess.source_map())
&& let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
&& let ItemKind::Impl(hir_impl) = &item.kind
&& let Some(trait_ref) = &hir_impl.of_trait
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(of_trait) = &hir_impl.of_trait
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
&& send_trait == trait_id
&& hir_impl.polarity == ImplPolarity::Positive
&& of_trait.polarity == ImplPolarity::Positive
&& let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
&& let self_ty = ty_trait_ref.instantiate_identity().self_ty()
&& let ty::Adt(adt_def, impl_trait_args) = self_ty.kind()
@@ -183,7 +183,7 @@ fn in_impl<'tcx>(
&& let item = cx.tcx.hir_expect_item(impl_def_id.expect_local())
&& let ItemKind::Impl(item) = &item.kind
&& let Some(of_trait) = &item.of_trait
&& let Some(seg) = of_trait.path.segments.last()
&& let Some(seg) = of_trait.trait_ref.path.segments.last()
&& let Res::Def(_, trait_id) = seg.res
&& trait_id == bin_op
&& let Some(generic_args) = seg.args
@@ -34,15 +34,15 @@
impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items: impl_items,
..
}) = item.kind
&& !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& let Some(eq_trait) = cx.tcx.lang_items().eq_trait()
&& trait_ref.path.res.def_id() == eq_trait
&& of_trait.trait_ref.path.res.def_id() == eq_trait
{
for impl_item in *impl_items {
for impl_item in impl_items {
if cx.tcx.item_name(impl_item.owner_id) == sym::ne {
span_lint_hir(
cx,
@@ -68,9 +68,9 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
let existing_name = map.get_mut(res).unwrap();
match of_trait {
Some(trait_ref) => {
Some(of_trait) => {
let mut methods_in_trait: BTreeSet<Symbol> = if let Node::TraitRef(TraitRef { path, .. }) =
cx.tcx.hir_node(trait_ref.hir_ref_id)
cx.tcx.hir_node(of_trait.trait_ref.hir_ref_id)
&& let Res::Def(DefKind::Trait, did) = path.res
{
// FIXME: if
@@ -26,16 +26,16 @@
impl<'tcx> LateLintPass<'tcx> for SerdeApi {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
items,
..
}) = item.kind
{
let did = trait_ref.path.res.def_id();
let did = of_trait.trait_ref.path.res.def_id();
if paths::SERDE_DE_VISITOR.matches(cx, did) {
let mut seen_str = None;
let mut seen_string = None;
for item in *items {
for item in items {
match cx.tcx.item_name(item.owner_id) {
sym::visit_str => seen_str = Some(cx.tcx.def_span(item.owner_id)),
sym::visit_string => seen_string = Some(cx.tcx.def_span(item.owner_id)),
@@ -48,10 +48,10 @@
impl<'tcx> LateLintPass<'tcx> for ToStringTraitImpl {
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'tcx>) {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = it.kind
&& let Some(trait_did) = trait_ref.trait_def_id()
&& let Some(trait_did) = of_trait.trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::ToString, trait_did)
{
span_lint_and_help(
@@ -137,9 +137,9 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt
// We exclude `impl` blocks generated from rustc's proc macros.
&& !cx.tcx.is_automatically_derived(owner_id.to_def_id())
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
&& let Some(of_trait) = impl_.of_trait
{
trait_.trait_def_id()
of_trait.trait_ref.trait_def_id()
} else {
None
}
@@ -242,8 +242,8 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local
// We exclude `impl` blocks generated from rustc's proc macros.
&& !cx.tcx.is_automatically_derived(owner_id.to_def_id())
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
&& let Some(trait_def_id) = trait_.trait_def_id()
&& let Some(of_trait) = impl_.of_trait
&& let Some(trait_def_id) = of_trait.trait_ref.trait_def_id()
// The trait is `ToString`.
&& cx.tcx.is_diagnostic_item(sym::ToString, trait_def_id)
{
@@ -8,7 +8,7 @@
use clippy_utils::visitors::{Descend, for_each_expr};
use hir::HirId;
use rustc_hir as hir;
use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
use rustc_hir::{Block, BlockCheckMode, Impl, ItemKind, Node, UnsafeSource};
use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::impl_lint_pass;
@@ -204,7 +204,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
let item_has_safety_comment = item_has_safety_comment(cx, item);
match (&item.kind, item_has_safety_comment) {
// lint unsafe impl without safety comment
(ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => {
(ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::No) if of_trait.safety.is_unsafe() => {
if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
&& !is_unsafe_from_proc_macro(cx, item.span)
{
@@ -228,7 +228,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
}
},
// lint safe impl with unnecessary safety comment
(ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => {
(ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::Yes(pos)) if of_trait.safety.is_safe() => {
if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
let (span, help_span) = mk_spans(pos);
+2 -2
View File
@@ -347,10 +347,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
if let ItemKind::Impl(Impl {
of_trait: Some(trait_ref),
of_trait: Some(of_trait),
..
}) = &item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
&& let Some(trait_id) = of_trait.trait_ref.trait_def_id()
{
cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
} else {
@@ -19,8 +19,8 @@
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
ImplItem, ImplItemKind, TraitImplHeader, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path,
QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
};
use rustc_lint::{EarlyContext, LateContext, LintContext};
use rustc_middle::ty::TyCtxt;
@@ -254,7 +254,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
ItemKind::Trait(_, _, Safety::Unsafe, ..)
| ItemKind::Impl(Impl {
safety: Safety::Unsafe, ..
of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), ..
}) => (Pat::Str("unsafe"), Pat::Str("}")),
ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
+2 -1
View File
@@ -528,8 +528,9 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
&& let ItemKind::Impl(impl_) = &item.kind
&& let Some(of_trait) = impl_.of_trait
{
return impl_.of_trait.as_ref();
return Some(&of_trait.trait_ref);
}
None
}
@@ -460,7 +460,8 @@ fn visit_block(&mut self, b: &'tcx Block<'_>) -> Self::Result {
}
fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
if let ItemKind::Impl(i) = &self.cx.tcx.hir_item(id).kind
&& i.safety.is_unsafe()
&& let Some(of_trait) = i.of_trait
&& of_trait.safety.is_unsafe()
{
ControlFlow::Break(())
} else {
+1 -1
View File
@@ -509,7 +509,7 @@ mod items {
impl () { }
impl <T> () { }
impl Default for () { }
impl const <T> Default for () { }
impl <T> const Default for () { }
}
/// ItemKind::MacCall
mod item_mac_call { }