Skip to content

Commit 4af7fa7

Browse files
committed
Auto merge of #133365 - compiler-errors:compare-impl-item, r=lcnr
Make `compare_impl_item` into a query Turns `compare_impl_item` into a query (generalizing the existing query for `compare_impl_const`), and uses that in `Instance::resolve` to fail resolution when an implementation is incompatible with the trait it comes from. Fixes #119701 Fixes #121127 Fixes #121411 Fixes #129075 Fixes #129127 Fixes #129214 Fixes #131294
2 parents 7442931 + 1e655ef commit 4af7fa7

File tree

18 files changed

+123
-228
lines changed

18 files changed

+123
-228
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use tracing::{debug, instrument};
3333
use ty::TypingMode;
3434
use {rustc_attr as attr, rustc_hir as hir};
3535

36-
use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty};
36+
use super::compare_impl_item::check_type_bounds;
3737
use super::*;
3838
use crate::check::intrinsicck::InlineAsmCtxt;
3939

@@ -1044,18 +1044,23 @@ fn check_impl_items_against_trait<'tcx>(
10441044
tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait");
10451045
continue;
10461046
};
1047-
match ty_impl_item.kind {
1048-
ty::AssocKind::Const => {
1049-
tcx.ensure().compare_impl_const((
1050-
impl_item.expect_local(),
1051-
ty_impl_item.trait_item_def_id.unwrap(),
1052-
));
1053-
}
1054-
ty::AssocKind::Fn => {
1055-
compare_impl_method(tcx, ty_impl_item, ty_trait_item, trait_ref);
1056-
}
1057-
ty::AssocKind::Type => {
1058-
compare_impl_ty(tcx, ty_impl_item, ty_trait_item, trait_ref);
1047+
1048+
let res = tcx.ensure().compare_impl_item(impl_item.expect_local());
1049+
1050+
if res.is_ok() {
1051+
match ty_impl_item.kind {
1052+
ty::AssocKind::Fn => {
1053+
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
1054+
tcx,
1055+
ty_impl_item,
1056+
ty_trait_item,
1057+
tcx.impl_trait_ref(ty_impl_item.container_id(tcx))
1058+
.unwrap()
1059+
.instantiate_identity(),
1060+
);
1061+
}
1062+
ty::AssocKind::Const => {}
1063+
ty::AssocKind::Type => {}
10591064
}
10601065
}
10611066

compiler/rustc_hir_analysis/src/check/compare_impl_item.rs

+36-32
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,25 @@ use tracing::{debug, instrument};
3333
use super::potentially_plural_count;
3434
use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
3535

36-
mod refine;
36+
pub(super) mod refine;
37+
38+
/// Call the query `tcx.compare_impl_item()` directly instead.
39+
pub(super) fn compare_impl_item(
40+
tcx: TyCtxt<'_>,
41+
impl_item_def_id: LocalDefId,
42+
) -> Result<(), ErrorGuaranteed> {
43+
let impl_item = tcx.associated_item(impl_item_def_id);
44+
let trait_item = tcx.associated_item(impl_item.trait_item_def_id.unwrap());
45+
let impl_trait_ref =
46+
tcx.impl_trait_ref(impl_item.container_id(tcx)).unwrap().instantiate_identity();
47+
debug!(?impl_trait_ref);
48+
49+
match impl_item.kind {
50+
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
51+
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
52+
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
53+
}
54+
}
3755

3856
/// Checks that a method from an impl conforms to the signature of
3957
/// the same method as declared in the trait.
@@ -44,22 +62,15 @@ mod refine;
4462
/// - `trait_m`: the method in the trait
4563
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
4664
#[instrument(level = "debug", skip(tcx))]
47-
pub(super) fn compare_impl_method<'tcx>(
65+
fn compare_impl_method<'tcx>(
4866
tcx: TyCtxt<'tcx>,
4967
impl_m: ty::AssocItem,
5068
trait_m: ty::AssocItem,
5169
impl_trait_ref: ty::TraitRef<'tcx>,
52-
) {
53-
let _: Result<_, ErrorGuaranteed> = try {
54-
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
55-
compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;
56-
refine::check_refining_return_position_impl_trait_in_trait(
57-
tcx,
58-
impl_m,
59-
trait_m,
60-
impl_trait_ref,
61-
);
62-
};
70+
) -> Result<(), ErrorGuaranteed> {
71+
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
72+
compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;
73+
Ok(())
6374
}
6475

6576
/// Checks a bunch of different properties of the impl/trait methods for
@@ -1721,17 +1732,12 @@ fn compare_generic_param_kinds<'tcx>(
17211732
Ok(())
17221733
}
17231734

1724-
/// Use `tcx.compare_impl_const` instead
1725-
pub(super) fn compare_impl_const_raw(
1726-
tcx: TyCtxt<'_>,
1727-
(impl_const_item_def, trait_const_item_def): (LocalDefId, DefId),
1735+
fn compare_impl_const<'tcx>(
1736+
tcx: TyCtxt<'tcx>,
1737+
impl_const_item: ty::AssocItem,
1738+
trait_const_item: ty::AssocItem,
1739+
impl_trait_ref: ty::TraitRef<'tcx>,
17281740
) -> Result<(), ErrorGuaranteed> {
1729-
let impl_const_item = tcx.associated_item(impl_const_item_def);
1730-
let trait_const_item = tcx.associated_item(trait_const_item_def);
1731-
let impl_trait_ref =
1732-
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
1733-
debug!(?impl_trait_ref);
1734-
17351741
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
17361742
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
17371743
check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?;
@@ -1862,19 +1868,17 @@ fn compare_const_predicate_entailment<'tcx>(
18621868
}
18631869

18641870
#[instrument(level = "debug", skip(tcx))]
1865-
pub(super) fn compare_impl_ty<'tcx>(
1871+
fn compare_impl_ty<'tcx>(
18661872
tcx: TyCtxt<'tcx>,
18671873
impl_ty: ty::AssocItem,
18681874
trait_ty: ty::AssocItem,
18691875
impl_trait_ref: ty::TraitRef<'tcx>,
1870-
) {
1871-
let _: Result<(), ErrorGuaranteed> = try {
1872-
compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
1873-
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
1874-
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
1875-
compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?;
1876-
check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)?;
1877-
};
1876+
) -> Result<(), ErrorGuaranteed> {
1877+
compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
1878+
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
1879+
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
1880+
compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?;
1881+
check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)
18781882
}
18791883

18801884
/// The equivalent of [compare_method_predicate_entailment], but for associated types

compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt;
1717
use rustc_trait_selection::traits::{ObligationCtxt, elaborate, normalize_param_env_or_error};
1818

1919
/// Check that an implementation does not refine an RPITIT from a trait method signature.
20-
pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
20+
pub(crate) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
2121
tcx: TyCtxt<'tcx>,
2222
impl_m: ty::AssocItem,
2323
trait_m: ty::AssocItem,

compiler/rustc_hir_analysis/src/check/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ pub fn provide(providers: &mut Providers) {
108108
adt_async_destructor,
109109
region_scope_tree,
110110
collect_return_position_impl_trait_in_trait_tys,
111-
compare_impl_const: compare_impl_item::compare_impl_const_raw,
111+
compare_impl_item: compare_impl_item::compare_impl_item,
112112
check_coroutine_obligations: check::check_coroutine_obligations,
113113
..*providers
114114
};

compiler/rustc_middle/src/query/mod.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -2311,10 +2311,13 @@ rustc_queries! {
23112311
desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
23122312
}
23132313

2314-
query compare_impl_const(
2315-
key: (LocalDefId, DefId)
2316-
) -> Result<(), ErrorGuaranteed> {
2317-
desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0) }
2314+
/// This takes the def-id of an associated item from a impl of a trait,
2315+
/// and checks its validity against the trait item it corresponds to.
2316+
///
2317+
/// Any other def id will ICE.
2318+
query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
2319+
desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) }
2320+
ensure_forwards_result_if_red
23182321
}
23192322

23202323
query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {

compiler/rustc_ty_utils/src/instance.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -216,15 +216,15 @@ fn resolve_associated_item<'tcx>(
216216

217217
let args = tcx.erase_regions(args);
218218

219-
// Check if we just resolved an associated `const` declaration from
220-
// a `trait` to an associated `const` definition in an `impl`, where
221-
// the definition in the `impl` has the wrong type (for which an
222-
// error has already been/will be emitted elsewhere).
223-
if leaf_def.item.kind == ty::AssocKind::Const
224-
&& trait_item_id != leaf_def.item.def_id
219+
// We check that the impl item is compatible with the trait item
220+
// because otherwise we may ICE in const eval due to type mismatches,
221+
// signature incompatibilities, etc.
222+
// NOTE: We could also only enforce this in `PostAnalysis`, which
223+
// is what CTFE and MIR inlining would care about anyways.
224+
if trait_item_id != leaf_def.item.def_id
225225
&& let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
226226
{
227-
tcx.compare_impl_const((leaf_def_item, trait_item_id))?;
227+
tcx.ensure().compare_impl_item(leaf_def_item)?;
228228
}
229229

230230
Some(ty::Instance::new(leaf_def.item.def_id, args))

tests/crashes/119701.rs

-21
This file was deleted.

tests/crashes/121127.rs

-23
This file was deleted.

tests/crashes/121411.rs

-13
This file was deleted.

tests/crashes/129075.rs

-16
This file was deleted.

tests/crashes/129127.rs

-21
This file was deleted.

tests/crashes/129214.rs

-30
This file was deleted.

tests/crashes/131294-2.rs

-25
This file was deleted.

tests/crashes/131294.rs

-16
This file was deleted.

tests/ui/const-generics/issues/issue-83765.stderr

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ note: ...which requires computing candidate for `<LazyUpdim<'_, T, <T as TensorD
2929
LL | trait TensorDimension {
3030
| ^^^^^^^^^^^^^^^^^^^^^
3131
= note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle
32-
note: cycle used when checking that `<impl at $DIR/issue-83765.rs:56:1: 56:97>` is well-formed
33-
--> $DIR/issue-83765.rs:56:1
32+
note: cycle used when checking assoc item `<impl at $DIR/issue-83765.rs:56:1: 56:97>::bget` is compatible with trait definition
33+
--> $DIR/issue-83765.rs:58:5
3434
|
35-
LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> {
36-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
35+
LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
36+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3737
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
3838

3939
error[E0308]: method not compatible with trait

0 commit comments

Comments
 (0)