Skip to content

fix: Test all generic args for trait when finding matching impl #13475

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

Merged
merged 3 commits into from
Oct 26, 2022

Conversation

lowr
Copy link
Contributor

@lowr lowr commented Oct 24, 2022

Addresses #13463 (comment)

When finding matching impl for a trait method, we've been testing the unifiability of self type. However, there can be multiple impl of a trait for the same type with different generic arguments for the trait. This patch takes it into account and tests the unifiability of all type arguments for the trait (the first being the self type) thus enables rust-analyzer to find the correct impl even in such cases.

@Veykril
Copy link
Member

Veykril commented Oct 24, 2022

@bors r+

@bors
Copy link
Contributor

bors commented Oct 24, 2022

📌 Commit 61fbde0 has been approved by Veykril

It is now in the queue for this repository.

@flodiebold
Copy link
Member

I think you should be able to unify the substitutions directly instead of looping manually? That would also take care of consts.

@flodiebold
Copy link
Member

Also, I think we have some bug report(s) that this fixes as well.

@bors
Copy link
Contributor

bors commented Oct 24, 2022

⌛ Testing commit 61fbde0 with merge 5b061b2...

bors added a commit that referenced this pull request Oct 24, 2022
fix: Test all type args for trait when finding matching impl

Addresses #13463 (comment)

When finding matching impl for a trait method, we've been testing the unifiability of self type. However, there can be multiple impl of a trait for the same type with different generic arguments for the trait. This patch takes it into account and tests the unifiability of all type arguments for the trait (the first being the self type) thus enables rust-analyzer to find the correct impl even in such cases.
@lowr
Copy link
Contributor Author

lowr commented Oct 24, 2022

@flodiebold I was pretty sure there's a way to do that! Are you talking about InferenceTable::try_unify(), which takes T: Zip instead of Ty?

Could someone r-?

@Veykril
Copy link
Member

Veykril commented Oct 24, 2022

bors r-
(wouldn't be a problem to do that in a follow up PR either)

@Veykril
Copy link
Member

Veykril commented Oct 24, 2022

@bors r-

@bors
Copy link
Contributor

bors commented Oct 24, 2022

☀️ Try build successful - checks-actions
Build commit: 5b061b2 (5b061b2218b2f849f22e89a93a15cfcadc27c050)

1 similar comment
@bors
Copy link
Contributor

bors commented Oct 24, 2022

☀️ Try build successful - checks-actions
Build commit: 5b061b2 (5b061b2218b2f849f22e89a93a15cfcadc27c050)

@lowr lowr force-pushed the fix/lookup-impl-method-trait-ref branch 2 times, most recently from 037208e to 324151d Compare October 24, 2022 13:58
@lowr lowr changed the title fix: Test all type args for trait when finding matching impl fix: Test all generic args for trait when finding matching impl Oct 24, 2022
@lowr lowr force-pushed the fix/lookup-impl-method-trait-ref branch from 324151d to 6410bb0 Compare October 24, 2022 14:07
@flodiebold
Copy link
Member

@flodiebold I was pretty sure there's a way to do that! Are you talking about InferenceTable::try_unify(), which takes T: Zip instead of Ty?

It seems to me we could just make unify generic?

@lowr lowr force-pushed the fix/lookup-impl-method-trait-ref branch from 6410bb0 to ed7481a Compare October 24, 2022 14:23

let goal = crate::Goal::all(Interner, wh_goals);
if !table
.unify(trait_ref.substitution.as_slice(Interner), expected_subst.as_slice(Interner))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should just have actual TraitRefs here, then we could just unify those

db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
trait_: TraitId,
name: &Name,
fn_subst: Substitution,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kind of weird to be passing the fn subst, but not the actual fn ID, right? we could just pass the trait subst, and then merge that with the trait_ parameter into a TraitRef

Copy link
Contributor Author

@lowr lowr Oct 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I feel weird too. This function is called from hir and I didn't want to let hir manipulate Substitutions (besides passing them around as-is). It's just my preference so can we just make new Substitution for the trait out of fn subst in hir layer?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm I think ideally we'd have some nice functions to get the trait ref from a function subst and so on. I think for now either would be fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that would be useful and an extension method would be good place for it I guess? Will try adding that.

@lowr lowr force-pushed the fix/lookup-impl-method-trait-ref branch from ed7481a to 67f1d8f Compare October 25, 2022 14:51
@lowr
Copy link
Contributor Author

lowr commented Oct 25, 2022

So I ended up restructuring the related methods.

  • hir-ty::method_resolution::lookup_impl_method() is now taking func id and func subst and is responsible for retrieving trait id and trait subst.
    • You can still pass any (unrelated) func id and func subst to the method, which I eventually want to forbid to prevent logical errors. One way to do this is to make an extension method for TyKind::FnDef, which ties up func id and subst, but we need to intern them in some code paths which would then immediately looked up, and that's... inefficient.
  • SourceAnalyzer::resolve_impl_method() has been merged into resolve_impl_method_or_trait_def() because all the callers of those methods return the original func id when the lookup failed.

@flodiebold I'd appreciate if you could take a look again. I think the weirdness is somewhat alleviated and it's more organized than before.

@flodiebold
Copy link
Member

@bors r+

@bors
Copy link
Contributor

bors commented Oct 26, 2022

📌 Commit 67f1d8f has been approved by flodiebold

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Oct 26, 2022

⌛ Testing commit 67f1d8f with merge feefbe7...

@bors
Copy link
Contributor

bors commented Oct 26, 2022

☀️ Test successful - checks-actions
Approved by: flodiebold
Pushing feefbe7 to master...

@bors bors merged commit feefbe7 into rust-lang:master Oct 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants