Skip to content

remove find_map_relevant_impl #108895

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

Closed
lcnr opened this issue Mar 8, 2023 · 5 comments · Fixed by #110514
Closed

remove find_map_relevant_impl #108895

lcnr opened this issue Mar 8, 2023 · 5 comments · Fixed by #110514
Assignees
Labels
C-cleanup Category: PRs that clean code up or issues documenting cleanup. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@lcnr
Copy link
Contributor

lcnr commented Mar 8, 2023

pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
self,
trait_def_id: DefId,
self_ty: Ty<'tcx>,
mut f: F,
) -> Option<T> {

This function iterates over all impls which may apply to self_ty and returns the first Some. Note that just because an impl is given to f it may not actually apply to the whole trait_ref (or deeply matches self_ty). Because of this it ends up being very easy to misuse. Let's go through a few incorrect uses of this function:

tcx.find_map_relevant_impl(trait_, ty, |impl_| {
let trait_ref = tcx.impl_trait_ref(impl_).expect("this is not an inherent impl");
// Check if these are the same type.
let impl_type = trait_ref.skip_binder().self_ty();
trace!(
"comparing type {} with kind {:?} against type {:?}",
impl_type,
impl_type.kind(),
ty
);
// Fast path: if this is a primitive simple `==` will work
// NOTE: the `match` is necessary; see #92662.
// this allows us to ignore generics because the user input
// may not include the generic placeholders
// e.g. this allows us to match Foo (user comment) with Foo<T> (actual type)
let saw_impl = impl_type == ty
|| match (impl_type.kind(), ty.kind()) {
(ty::Adt(impl_def, _), ty::Adt(ty_def, _)) => {
debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did(), ty_def.did());
impl_def.did() == ty_def.did()
}
_ => false,
};
if saw_impl { Some((impl_, trait_)) } else { None }
})

only looks at the first maybe applicable impl even if there are multiple, idk how exactly that function is used, but it should be wrong 😅

let get_trait_impl = |trait_def_id| {
self.tcx.find_map_relevant_impl(trait_def_id, trait_ref.skip_binder().self_ty(), Some)
};

Checks whether another trait with the same path has an impl for self_ty. Note that this emits the error message if 2 versions of a crate are used, but the substs implement neither of the traits.

self.tcx.find_map_relevant_impl(id, proj.projection_ty.self_ty(), |did| {

whatever this is doing 😅 but this should be usable to point to an impl which doesn't actually apply.

I would like to change all the uses of find_map_relevant_impl to instead use for_each_relevant_impl.

@lcnr lcnr added C-cleanup Category: PRs that clean code up or issues documenting cleanup. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. labels Mar 8, 2023
@jyn514
Copy link
Member

jyn514 commented Mar 8, 2023

Oh hi, I wrote that rustdoc code 😆

only looks at the first maybe applicable impl even if there are multiple, idk how exactly that function is used, but it should be wrong

What does it mean for multiple impls to be applicable? Like different generic arguments for the same generic type? That should be ok - rustdoc is just checking if these functions exist at all for the unsubstituted ty, not whether they can actually be called. e.g. it's ok for it to have a false positive on impl Clone for Vec<Mutex> as long as there's some type T for which Vec<T>: Clone.

@jyn514 jyn514 closed this as completed Mar 8, 2023
@jyn514 jyn514 reopened this Mar 8, 2023
@jyn514
Copy link
Member

jyn514 commented Mar 8, 2023

(hate mobile GitHub 😠 )

@vincenzopalazzo
Copy link
Member

vincenzopalazzo commented Mar 9, 2023

@rustbot claim

This looks fun!

@Noratrieb Noratrieb added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 5, 2023
@compiler-errors
Copy link
Member

@vincenzopalazzo are you working on this? I think I'd like to finish this unless you've already put a lot of time into this.

@vincenzopalazzo
Copy link
Member

@compiler-errors Sorry I did not have time, so take it. Can you cc me on the PR when it is out I would like to see the code 😄

@vincenzopalazzo vincenzopalazzo removed their assignment Apr 18, 2023
@compiler-errors compiler-errors self-assigned this Apr 18, 2023
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 22, 2023
…levant_impl, r=b-naber

Remove `find_map_relevant_impl`

Fixes rust-lang#108895
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 22, 2023
…levant_impl, r=b-naber

Remove `find_map_relevant_impl`

Fixes rust-lang#108895
compiler-errors added a commit to compiler-errors/rust that referenced this issue Apr 22, 2023
…levant_impl, r=b-naber

Remove `find_map_relevant_impl`

Fixes rust-lang#108895
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 23, 2023
…levant_impl, r=b-naber

Remove `find_map_relevant_impl`

Fixes rust-lang#108895
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Apr 24, 2023
…levant_impl, r=b-naber

Remove `find_map_relevant_impl`

Fixes rust-lang#108895
@bors bors closed this as completed in d60c64a Apr 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-cleanup Category: PRs that clean code up or issues documenting cleanup. E-hard Call for participation: Hard difficulty. Experience needed to fix: A lot. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants