Make compare_impl_item into a query

This commit is contained in:
Michael Goulet 2024-11-23 04:48:01 +00:00
parent e48ddd8a0b
commit a3623f20ae
16 changed files with 84 additions and 228 deletions

View file

@ -33,7 +33,7 @@ use tracing::{debug, instrument};
use ty::TypingMode; use ty::TypingMode;
use {rustc_attr as attr, rustc_hir as hir}; use {rustc_attr as attr, rustc_hir as hir};
use super::compare_impl_item::{check_type_bounds, compare_impl_method, compare_impl_ty}; use super::compare_impl_item::check_type_bounds;
use super::*; use super::*;
use crate::check::intrinsicck::InlineAsmCtxt; use crate::check::intrinsicck::InlineAsmCtxt;
@ -1044,20 +1044,8 @@ fn check_impl_items_against_trait<'tcx>(
tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait"); tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait");
continue; continue;
}; };
match ty_impl_item.kind {
ty::AssocKind::Const => { let _ = tcx.ensure().compare_impl_item(impl_item.expect_local());
tcx.ensure().compare_impl_const((
impl_item.expect_local(),
ty_impl_item.trait_item_def_id.unwrap(),
));
}
ty::AssocKind::Fn => {
compare_impl_method(tcx, ty_impl_item, ty_trait_item, trait_ref);
}
ty::AssocKind::Type => {
compare_impl_ty(tcx, ty_impl_item, ty_trait_item, trait_ref);
}
}
check_specialization_validity( check_specialization_validity(
tcx, tcx,

View file

@ -35,6 +35,24 @@ use crate::errors::{LifetimesOrBoundsMismatchOnTrait, MethodShouldReturnFuture};
mod refine; mod refine;
/// Call the query `tcx.compare_impl_item()` directly instead.
pub(super) fn compare_impl_item(
tcx: TyCtxt<'_>,
impl_item_def_id: LocalDefId,
) -> 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();
debug!(?impl_trait_ref);
match impl_item.kind {
ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
}
}
/// Checks that a method from an impl conforms to the signature of /// Checks that a method from an impl conforms to the signature of
/// the same method as declared in the trait. /// the same method as declared in the trait.
/// ///
@ -44,22 +62,21 @@ mod refine;
/// - `trait_m`: the method in the trait /// - `trait_m`: the method in the trait
/// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation /// - `impl_trait_ref`: the TraitRef corresponding to the trait implementation
#[instrument(level = "debug", skip(tcx))] #[instrument(level = "debug", skip(tcx))]
pub(super) fn compare_impl_method<'tcx>( fn compare_impl_method<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
impl_m: ty::AssocItem, impl_m: ty::AssocItem,
trait_m: ty::AssocItem, trait_m: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>, impl_trait_ref: ty::TraitRef<'tcx>,
) { ) -> Result<(), ErrorGuaranteed> {
let _: Result<_, ErrorGuaranteed> = try { check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?;
check_method_is_structurally_compatible(tcx, impl_m, trait_m, impl_trait_ref, false)?; compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?;
compare_method_predicate_entailment(tcx, impl_m, trait_m, impl_trait_ref)?; refine::check_refining_return_position_impl_trait_in_trait(
refine::check_refining_return_position_impl_trait_in_trait( tcx,
tcx, impl_m,
impl_m, trait_m,
trait_m, impl_trait_ref,
impl_trait_ref, );
); Ok(())
};
} }
/// Checks a bunch of different properties of the impl/trait methods for /// Checks a bunch of different properties of the impl/trait methods for
@ -1721,17 +1738,12 @@ fn compare_generic_param_kinds<'tcx>(
Ok(()) Ok(())
} }
/// Use `tcx.compare_impl_const` instead fn compare_impl_const<'tcx>(
pub(super) fn compare_impl_const_raw( tcx: TyCtxt<'tcx>,
tcx: TyCtxt<'_>, impl_const_item: ty::AssocItem,
(impl_const_item_def, trait_const_item_def): (LocalDefId, DefId), trait_const_item: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>,
) -> Result<(), ErrorGuaranteed> { ) -> Result<(), ErrorGuaranteed> {
let impl_const_item = tcx.associated_item(impl_const_item_def);
let trait_const_item = tcx.associated_item(trait_const_item_def);
let impl_trait_ref =
tcx.impl_trait_ref(impl_const_item.container_id(tcx)).unwrap().instantiate_identity();
debug!(?impl_trait_ref);
compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?; compare_number_of_generics(tcx, impl_const_item, trait_const_item, false)?;
compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?; compare_generic_param_kinds(tcx, impl_const_item, trait_const_item, false)?;
check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?; check_region_bounds_on_impl_item(tcx, impl_const_item, trait_const_item, false)?;
@ -1862,19 +1874,17 @@ fn compare_const_predicate_entailment<'tcx>(
} }
#[instrument(level = "debug", skip(tcx))] #[instrument(level = "debug", skip(tcx))]
pub(super) fn compare_impl_ty<'tcx>( fn compare_impl_ty<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
impl_ty: ty::AssocItem, impl_ty: ty::AssocItem,
trait_ty: ty::AssocItem, trait_ty: ty::AssocItem,
impl_trait_ref: ty::TraitRef<'tcx>, impl_trait_ref: ty::TraitRef<'tcx>,
) { ) -> Result<(), ErrorGuaranteed> {
let _: Result<(), ErrorGuaranteed> = try { compare_number_of_generics(tcx, impl_ty, trait_ty, false)?;
compare_number_of_generics(tcx, impl_ty, trait_ty, false)?; compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?;
compare_generic_param_kinds(tcx, impl_ty, trait_ty, false)?; check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?;
check_region_bounds_on_impl_item(tcx, impl_ty, trait_ty, false)?; compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?;
compare_type_predicate_entailment(tcx, impl_ty, trait_ty, impl_trait_ref)?; check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)
check_type_bounds(tcx, trait_ty, impl_ty, impl_trait_ref)?;
};
} }
/// The equivalent of [compare_method_predicate_entailment], but for associated types /// The equivalent of [compare_method_predicate_entailment], but for associated types

View file

@ -108,7 +108,7 @@ pub fn provide(providers: &mut Providers) {
adt_async_destructor, adt_async_destructor,
region_scope_tree, region_scope_tree,
collect_return_position_impl_trait_in_trait_tys, collect_return_position_impl_trait_in_trait_tys,
compare_impl_const: compare_impl_item::compare_impl_const_raw, compare_impl_item: compare_impl_item::compare_impl_item,
check_coroutine_obligations: check::check_coroutine_obligations, check_coroutine_obligations: check::check_coroutine_obligations,
..*providers ..*providers
}; };

View file

@ -2311,10 +2311,13 @@ rustc_queries! {
desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 } desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
} }
query compare_impl_const( /// This takes the def-id of an associated item from a impl of a trait,
key: (LocalDefId, DefId) /// and checks its validity against the trait item it corresponds to.
) -> Result<(), ErrorGuaranteed> { ///
desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0) } /// Any other def id will ICE.
query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) }
ensure_forwards_result_if_red
} }
query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] { query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {

View file

@ -216,15 +216,13 @@ fn resolve_associated_item<'tcx>(
let args = tcx.erase_regions(args); let args = tcx.erase_regions(args);
// Check if we just resolved an associated `const` declaration from // We check that the impl item is compatible with the trait item
// a `trait` to an associated `const` definition in an `impl`, where // because otherwise we may ICE in const eval due to type mismatches,
// the definition in the `impl` has the wrong type (for which an // signature incompatibilities, etc.
// error has already been/will be emitted elsewhere). if trait_item_id != leaf_def.item.def_id
if leaf_def.item.kind == ty::AssocKind::Const
&& trait_item_id != leaf_def.item.def_id
&& let Some(leaf_def_item) = leaf_def.item.def_id.as_local() && let Some(leaf_def_item) = leaf_def.item.def_id.as_local()
{ {
tcx.compare_impl_const((leaf_def_item, trait_item_id))?; tcx.ensure().compare_impl_item(leaf_def_item)?;
} }
Some(ty::Instance::new(leaf_def.item.def_id, args)) Some(ty::Instance::new(leaf_def.item.def_id, args))

View file

@ -1,21 +0,0 @@
//@ known-bug: #119701
#![feature(const_trait_impl, generic_const_exprs)]
fn main() {
let _ = process::<()>([()]);
}
fn process<T: const Trait>() -> [(); T::make(2)] {
input
}
#[const_trait]
trait Trait {
fn make(input: u8) -> usize;
}
impl const Trait for () {
fn make(input: usize) -> usize {
input / 2
}
}

View file

@ -1,23 +0,0 @@
//@ known-bug: #121127
//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes -C debuginfo=2
// Note that as of PR#123949 this only crashes with debuginfo enabled
#![feature(specialization)]
pub trait Foo {
fn abc() -> u32;
}
pub trait Marker {}
impl<T> Foo for T {
default fn abc(f: fn(&T), t: &T) -> u32 {
16
}
}
impl<T: Marker> Foo for T {
fn def() -> u32 {
Self::abc()
}
}

View file

@ -1,13 +0,0 @@
//@ known-bug: #121411
#![feature(const_trait_impl)]
#[const_trait]
trait Foo {
fn into_iter(&self) {}
}
impl const Foo for () {
fn into_iter(a: u32, b: u32) {}
}
const _: () = Foo::into_iter(&());

View file

@ -1,16 +0,0 @@
//@ known-bug: rust-lang/rust#129075
//@ compile-flags: -Zvalidate-mir -Zinline-mir=yes
struct Foo<T>([T; 2]);
impl<T: Default + Copy> Default for Foo<T> {
fn default(&mut self) -> Self {
Foo([Default::default(); 2])
}
}
fn field_array() {
let a: i32;
let b;
Foo([a, b]) = Default::default();
}

View file

@ -1,21 +0,0 @@
//@ known-bug: rust-lang/rust#129127
//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always
pub struct Rows<'a>();
impl<'a> Iterator for Rows<'a> {
type Item = ();
fn next() -> Option<Self::Item> {
let mut rows = Rows();
rows.map(|row| row).next()
}
}
fn main() {
let mut rows = Rows();
rows.next();
}

View file

@ -1,30 +0,0 @@
//@ known-bug: rust-lang/rust#129214
//@ compile-flags: -Zvalidate-mir -Copt-level=3 --crate-type=lib
trait to_str {}
trait map<T> {
fn map<U, F>(&self, f: F) -> Vec<U>
where
F: FnMut(&Box<usize>) -> U;
}
impl<T> map<T> for Vec<T> {
fn map<U, F>(&self, mut f: F) -> Vec<U>
where
F: FnMut(&T) -> U,
{
let mut r = Vec::new();
for i in self {
r.push(f(i));
}
r
}
}
fn foo<U, T: map<U>>(x: T) -> Vec<String> {
x.map(|_e| "hi".to_string())
}
pub fn main() {
assert_eq!(foo(vec![1]), ["hi".to_string()]);
}

View file

@ -1,25 +0,0 @@
//@ known-bug: #131294
//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always
// https://github.com/rust-lang/rust/issues/131294#issuecomment-2395088049 second comment
struct Rows;
impl Iterator for Rows {
type Item = String;
fn next() -> Option<String> {
let args = format_args!("Hello world");
{
match args.as_str() {
Some(t) => t.to_owned(),
None => String::new(),
}
}
.into()
}
}
fn main() {
Rows.next();
}

View file

@ -1,16 +0,0 @@
//@ known-bug: #131294
//@ compile-flags: -Zmir-opt-level=5 -Zvalidate-mir -Zcross-crate-inline-threshold=always
struct Rows;
impl Iterator for Rows {
type Item = String;
fn next() -> Option<Self::Item> {
std::fmt::format(format_args!("Hello world")).into()
}
}
fn main() {
Rows.next();
}

View file

@ -29,11 +29,11 @@ note: ...which requires computing candidate for `<LazyUpdim<'_, T, <T as TensorD
LL | trait TensorDimension { LL | trait TensorDimension {
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle = note: ...which again requires resolving instance `<LazyUpdim<'_, T, <T as TensorDimension>::DIM, DIM> as TensorDimension>::DIM`, completing the cycle
note: cycle used when checking that `<impl at $DIR/issue-83765.rs:56:1: 56:97>` is well-formed note: cycle used when checking assoc item `<impl at $DIR/issue-83765.rs:56:1: 56:97>::bget` is compatible with trait definition
--> $DIR/issue-83765.rs:56:1 --> $DIR/issue-83765.rs:58:5
| |
LL | impl<'a, T: Broadcastable, const DIM: usize> Broadcastable for LazyUpdim<'a, T, { T::DIM }, DIM> { LL | fn bget(&self, index: [usize; DIM]) -> Option<Self::Element> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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 = 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
error[E0308]: method not compatible with trait error[E0308]: method not compatible with trait

View file

@ -1,4 +1,4 @@
//@ known-bug: #112623 // Make sure we don't ICE when evaluating a trait whose impl has a bad signature.
#![feature(const_trait_impl)] #![feature(const_trait_impl)]
@ -15,6 +15,7 @@ struct FortyTwo;
impl const Value for FortyTwo { impl const Value for FortyTwo {
fn value() -> i64 { fn value() -> i64 {
//~^ ERROR method `value` has an incompatible type for trait
42 42
} }
} }

View file

@ -0,0 +1,21 @@
error[E0053]: method `value` has an incompatible type for trait
--> $DIR/eval-bad-signature.rs:17:19
|
LL | fn value() -> i64 {
| ^^^ expected `u32`, found `i64`
|
note: type in trait
--> $DIR/eval-bad-signature.rs:7:19
|
LL | fn value() -> u32;
| ^^^
= note: expected signature `fn() -> u32`
found signature `fn() -> i64`
help: change the output type to match the trait
|
LL | fn value() -> u32 {
| ~~~
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0053`.