-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Method lookup goes down the auto-deref rabbit hole when it doesn't need to #19509
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
Comments
Why was this issue closed? I tried on th playpen and it still gives the same error. |
This code still fails with the same error in Rust 1.5.0-nightly (after updating it to match the current |
Also reported by @skeleten |
What happens is that method probing first collects all the types in the deref chain and only then attempts probing. If a method wasn't found due to reaching the recursion limit, a recursion-limit-specific error could be used, but otherwise any result can be considered valid (ambiguities can only exist at the same deref level, not between levels). |
For reference, the adjusted code I'll be testing against: use std::ops::Deref;
pub struct Foo {
baz: Bar,
}
pub struct Bar;
impl Foo {
pub fn foo_method(&self) {
/* do something, doesn't really matter */
}
}
impl Bar {
pub fn bar_method(&self) {
}
}
impl Deref for Foo {
type Target = Bar;
fn deref<'a>(&'a self) -> &'a Self::Target {
&self.baz
}
}
impl Deref for Bar {
type Target = Foo;
fn deref<'a>(&'a self) -> &'a Self::Target {
panic!()
}
}
fn main() {
let foo = Foo {
baz: Bar,
};
let bar = Bar;
// should work
foo.bar_method();
// should compile but panic on runtime
bar.foo_method();
} |
So, I'm not entirely convinced this is a bug. I'd certainly want to think carefully about any particular fix. For example, stopping at the recursion limit doesn't feel very good to me. IIRC (and this code has changed enough that my memory could easily be rusty (pun intended)), while we are expanding out the candidates, it can easily happen that a candidate after N derefs inserts something which is applicable to N-k derefs. For example, if we have a method like:
then if we have a It seems like stopping when we reach a cycle might be ok, but I don't like doing anything upon exceeding the recursion depth but reporting some sort of error. That has proven very hard to reason about in the past: the recursion depth is basically supposed to be the point where the compiler throws up its hands and says "this compile neither succeeds nor fails because I got stuck". |
changing to T-lang because I think there is a language question here of the expected semantics of recursive autoderef. |
IMHO, the language should use the type that requires the least |
triage: P-low We discussed this in the @rust-lang/lang meeting some today. General conclusion was that if we can in fact detect a cycle, that is probably OK. It's worth pointing out there is some code in trait matching that aims to detect similar cycles -- it does have some problems around regions though -- but also that we can probably ignore regions for the purposes of establishing these cycles. This may take a bit of investigation. However, basically if we DO detect cycles the proper way (not merely by exceeding the recursion limit), then it seems ok to permit cutting off the method call candidate search there. Classifying as low priority because while this use case would be nice to support, it's not urgent. |
According to src/librustc_typeck/check/method/README.rs looking up all the deref's is just the first step of the method probing; Do you think maintaining a collection of all previously seen types and terminating once we see a type for the second time would be a valid solution to this issue? Edit: I mean like this |
No, because you could always construct new types at every level using generics. |
Triage: not aware of any movement here. |
Triage: no change |
fix(ide-assists): remove `AssistKind::None`
Here's a pathological example of two types, each implementing
Deref
on the other:Even though
Rc<T>
implementsClone
and thus has aclone
method, method resolution still tries to look up methods available via deref. This also happens for trying to call inherent methods on aFoo
directly (without usingRc
).Update:
Modern code on playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=2ca8f056b69c0cd8e4ce0365a6356f02
Current error (as of 2024):
The text was updated successfully, but these errors were encountered: