Skip to content

Limit impl_trait_header query to only trait impls #144607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -682,7 +682,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
let my_def = self.body.source.def_id();
let Some(td) =
self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
self.infcx.tcx.impl_of_assoc(my_def).and_then(|x| self.infcx.tcx.impl_opt_trait_id(x))
else {
return (false, false, None);
};
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// subroutine's self-type.
if let Some(impl_def_id) = cx.tcx.impl_of_assoc(instance.def_id()) {
// If the method does *not* belong to a trait, proceed
if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
if !cx.tcx.impl_is_of_trait(impl_def_id) {
let impl_self_ty = cx.tcx.instantiate_and_normalize_erasing_regions(
instance.args,
cx.typing_env(),
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_const_eval/src/const_eval/fn_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;
fn parent_impl_or_trait_constness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Constness {
let parent_id = tcx.local_parent(def_id);
match tcx.def_kind(parent_id) {
DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).unwrap().constness,
DefKind::Impl { of_trait: true } => tcx.impl_trait_header(parent_id).constness,
DefKind::Trait => {
if tcx.is_const_trait(parent_id.into()) {
hir::Constness::Const
Expand Down
9 changes: 3 additions & 6 deletions compiler/rustc_hir_analysis/src/check/always_applicable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,7 @@ fn ensure_impl_params_and_item_params_correspond<'tcx>(
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
ty::ImplPolarity::Negative => "!",
};
let trait_name = tcx
.item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
let trait_name = tcx.item_name(tcx.impl_trait_id(impl_def_id.to_def_id()));
let mut err = struct_span_code_err!(
tcx.dcx(),
impl_span,
Expand Down Expand Up @@ -187,8 +186,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);

let impl_span = tcx.def_span(impl_def_id.to_def_id());
let trait_name = tcx
.item_name(tcx.trait_id_of_impl(impl_def_id.to_def_id()).expect("expected impl of trait"));
let trait_name = tcx.item_name(tcx.impl_trait_id(impl_def_id.to_def_id()));
let polarity = match tcx.impl_polarity(impl_def_id) {
ty::ImplPolarity::Positive | ty::ImplPolarity::Reservation => "",
ty::ImplPolarity::Negative => "!",
Expand All @@ -212,8 +210,7 @@ fn ensure_impl_predicates_are_implied_by_item_defn<'tcx>(
ty::EarlyBinder::bind(tcx.param_env(adt_def_id)).instantiate(tcx, adt_to_impl_args);

let fresh_impl_args = infcx.fresh_args_for_item(impl_span, impl_def_id.to_def_id());
let fresh_adt_ty =
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate(tcx, fresh_impl_args).self_ty();
let fresh_adt_ty = tcx.impl_trait_ref(impl_def_id).instantiate(tcx, fresh_impl_args).self_ty();

ocx.eq(&ObligationCause::dummy_with_span(impl_span), adt_env, fresh_adt_ty, impl_adt_ty)
.expect("equating fully generic trait ref should never fail");
Expand Down
8 changes: 3 additions & 5 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -806,10 +806,10 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(),
DefKind::Impl { of_trait } => {
tcx.ensure_ok().generics_of(def_id);
tcx.ensure_ok().type_of(def_id);
tcx.ensure_ok().impl_trait_header(def_id);
tcx.ensure_ok().predicates_of(def_id);
tcx.ensure_ok().associated_items(def_id);
if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) {
if of_trait {
let impl_trait_header = tcx.impl_trait_header(def_id);
res = res.and(
tcx.ensure_ok()
.coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id),
Expand Down Expand Up @@ -1194,9 +1194,7 @@ fn check_impl_items_against_trait<'tcx>(
tcx,
ty_impl_item,
ty_trait_item,
tcx.impl_trait_ref(ty_impl_item.container_id(tcx))
.unwrap()
.instantiate_identity(),
tcx.impl_trait_ref(ty_impl_item.container_id(tcx)).instantiate_identity(),
);
}
ty::AssocKind::Const { .. } => {}
Expand Down
10 changes: 4 additions & 6 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ pub(super) fn compare_impl_item(
) -> Result<(), ErrorGuaranteed> {
let impl_item = tcx.associated_item(impl_item_def_id);
let trait_item = tcx.associated_item(impl_item.trait_item_def_id.unwrap());
let impl_trait_ref =
tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap().instantiate_identity();
let impl_trait_ref = tcx.impl_trait_ref(impl_item.container_id(tcx)).instantiate_identity();
debug!(?impl_trait_ref);

match impl_item.kind {
Expand Down Expand Up @@ -445,10 +444,9 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m_def_id: LocalDefId,
) -> Result<&'tcx DefIdMap<ty::EarlyBinder<'tcx, Ty<'tcx>>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_trait_ref =
tcx.impl_trait_ref(impl_m.impl_container(tcx).unwrap()).unwrap().instantiate_identity();
let impl_m = tcx.associated_item(impl_m_def_id.to_def_id());
let trait_m = tcx.associated_item(impl_m.trait_item_def_id.unwrap());
let impl_trait_ref = tcx.impl_trait_ref(tcx.parent(impl_m.def_id)).instantiate_identity();
// First, check a few of the same things as `compare_impl_method`,
// just so we don't ICE during instantiation later.
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, true)?;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ fn missing_items_err(
let snippet = with_types_for_signature!(suggestion_signature(
tcx,
trait_item,
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity(),
tcx.impl_trait_ref(impl_def_id).instantiate_identity(),
));
let code = format!("{padding}{snippet}\n{padding}");
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
Expand Down
78 changes: 40 additions & 38 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,47 +245,49 @@ 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));

crate::impl_wf_check::check_impl_wf(tcx, def_id)?;
crate::impl_wf_check::check_impl_wf(tcx, def_id, impl_.of_trait.is_some())?;
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 impl_.of_trait.is_some() {
let header = tcx.impl_trait_header(def_id);
let is_auto = tcx.trait_is_auto(header.trait_ref.skip_binder().def_id);
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());
}
}
Some(ty::ImplPolarity::Reservation) => {
// FIXME: what amount of WF checking do we need for reservation impls?
// We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
match header.polarity {
// `None` means this is an inherent impl
ty::ImplPolarity::Positive => {
res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
}
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"
)
.emit());
}
}
ty::ImplPolarity::Reservation => {
// FIXME: what amount of WF checking do we need for reservation impls?
}
}
} else {
res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
}
res
}
Expand Down Expand Up @@ -1271,7 +1273,7 @@ fn check_impl<'tcx>(
// `#[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).
let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity();
let trait_ref = tcx.impl_trait_ref(item.owner_id).instantiate_identity();
// 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)?;
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/coherence/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ pub(crate) fn coerce_unsized_info<'tcx>(
let unsize_trait = tcx.require_lang_item(LangItem::Unsize, span);

let source = tcx.type_of(impl_did).instantiate_identity();
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
let trait_ref = tcx.impl_trait_ref(impl_did).instantiate_identity();

assert_eq!(trait_ref.def_id, coerce_unsized_trait);
let target = trait_ref.args.type_at(1);
Expand Down Expand Up @@ -714,7 +714,7 @@ fn visit_implementation_of_coerce_pointee_validity(
checker: &Checker<'_>,
) -> Result<(), ErrorGuaranteed> {
let tcx = checker.tcx;
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).unwrap().instantiate_identity().self_ty();
let self_ty = tcx.impl_trait_ref(checker.impl_def_id).instantiate_identity().self_ty();
let span = tcx.def_span(checker.impl_def_id);
if !tcx.is_builtin_derived(checker.impl_def_id.into()) {
return Err(tcx.dcx().emit_err(errors::CoercePointeeNoUserValidityAssertion { span }));
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/coherence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed>
let mut res = tcx.ensure_ok().specialization_graph_of(def_id);

for &impl_def_id in impls {
let impl_header = tcx.impl_trait_header(impl_def_id).unwrap();
let impl_header = tcx.impl_trait_header(impl_def_id);
let trait_ref = impl_header.trait_ref.instantiate_identity();
let trait_def = tcx.trait_def(trait_ref.def_id);

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/coherence/orphan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub(crate) fn orphan_check_impl(
tcx: TyCtxt<'_>,
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
let trait_ref = tcx.impl_trait_ref(impl_def_id).instantiate_identity();
trait_ref.error_reported()?;

match orphan_check(tcx, impl_def_id, OrphanCheckMode::Proper) {
Expand Down Expand Up @@ -292,7 +292,7 @@ fn orphan_check<'tcx>(
) -> Result<(), OrphanCheckErr<TyCtxt<'tcx>, FxIndexSet<DefId>>> {
// We only accept this routine to be invoked on implementations
// of a trait, not inherent implementations.
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
let trait_ref = tcx.impl_trait_ref(impl_def_id);
debug!(trait_ref = ?trait_ref.skip_binder());

// If the *trait* is local to the crate, ok.
Expand Down
26 changes: 14 additions & 12 deletions compiler/rustc_hir_analysis/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1291,24 +1291,26 @@ pub fn suggest_impl_trait<'tcx>(
None
}

fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTraitHeader<'_>> {
fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplTraitHeader<'_> {
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 selfty = tcx.type_of(def_id).instantiate_identity();
let ast_trait_ref = impl_
.of_trait
.as_ref()
.unwrap_or_else(|| panic!("expected impl trait, found inherent impl on {def_id:?}"));
let selfty = tcx.type_of(def_id).instantiate_identity();

check_impl_constness(tcx, impl_.constness, ast_trait_ref);
check_impl_constness(tcx, impl_.constness, ast_trait_ref);

let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_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,
}
})
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,
}
}

fn check_impl_constness(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir_analysis/src/collect/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {

let vtable_entries = match tcx.hir_item(id).kind {
hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => {
let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
let trait_ref = tcx.impl_trait_ref(def_id).instantiate_identity();
if trait_ref.has_non_region_param() {
tcx.dcx().span_err(
attr.span(),
Expand Down
20 changes: 9 additions & 11 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -496,17 +496,15 @@ pub(super) fn impl_super_outlives(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
tcx.impl_trait_header(def_id).expect("expected an impl of trait").trait_ref.map_bound(
|trait_ref| {
let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
matches!(
clause.kind().skip_binder(),
ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
)
}))
},
)
tcx.impl_trait_header(def_id).trait_ref.map_bound(|trait_ref| {
let clause: ty::Clause<'_> = trait_ref.upcast(tcx);
tcx.mk_clauses_from_iter(util::elaborate(tcx, [clause]).filter(|clause| {
matches!(
clause.kind().skip_binder(),
ty::ClauseKind::TypeOutlives(_) | ty::ClauseKind::RegionOutlives(_)
)
}))
})
}

struct AssocTyToOpaque<'tcx> {
Expand Down
20 changes: 10 additions & 10 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen

let impl_assoc_identity_args = ty::GenericArgs::identity_for_item(tcx, def_id);
let impl_def_id = tcx.parent(fn_def_id);
let impl_trait_ref_args =
tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity().args;
let impl_trait_ref_args = tcx.impl_trait_ref(impl_def_id).instantiate_identity().args;

let impl_assoc_args =
impl_assoc_identity_args.rebase_onto(tcx, impl_def_id, impl_trait_ref_args);
Expand Down Expand Up @@ -158,9 +157,8 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
match item.kind {
ItemKind::Impl(impl_) => {
if impl_.defaultness.is_default() {
is_default_impl_trait = tcx
.impl_trait_ref(def_id)
.map(|t| ty::Binder::dummy(t.instantiate_identity()));
is_default_impl_trait =
Some(ty::Binder::dummy(tcx.impl_trait_ref(def_id).instantiate_identity()));
}
}
ItemKind::Trait(_, _, _, _, _, self_bounds, ..)
Expand Down Expand Up @@ -350,9 +348,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// before uses of `U`. This avoids false ambiguity errors
// in trait checking. See `setup_constraining_predicates`
// for details.
if let Node::Item(&Item { kind: ItemKind::Impl { .. }, .. }) = node {
if let Node::Item(&Item { kind: ItemKind::Impl(impl_), .. }) = node {
let self_ty = tcx.type_of(def_id).instantiate_identity();
let trait_ref = tcx.impl_trait_ref(def_id).map(ty::EarlyBinder::instantiate_identity);
let trait_ref =
impl_.of_trait.is_some().then(|| tcx.impl_trait_ref(def_id).instantiate_identity());
cgp::setup_constraining_predicates(
tcx,
&mut predicates,
Expand Down Expand Up @@ -460,11 +459,12 @@ fn const_evaluatable_predicates_of<'tcx>(
}

if let hir::Node::Item(item) = node
&& let hir::ItemKind::Impl(_) = item.kind
&& let hir::ItemKind::Impl(impl_) = item.kind
{
if let Some(of_trait) = tcx.impl_trait_ref(def_id) {
if impl_.of_trait.is_some() {
debug!("visit impl trait_ref");
of_trait.instantiate_identity().visit_with(&mut collector);
let trait_ref = tcx.impl_trait_ref(def_id);
trait_ref.instantiate_identity().visit_with(&mut collector);
}

debug!("visit self_ty");
Expand Down
Loading
Loading