Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upMethod lookup goes down the auto-deref rabbit hole when it doesn't need to #19509
Comments
tomjakubowski
closed this
Dec 4, 2014
This comment has been minimized.
This comment has been minimized.
|
Why was this issue closed? I tried on th playpen and it still gives the same error. |
This comment has been minimized.
This comment has been minimized.
|
This code still fails with the same error in Rust 1.5.0-nightly (after updating it to match the current |
This comment has been minimized.
This comment has been minimized.
|
Also reported by @skeleten |
brson
reopened this
Oct 8, 2015
brson
added
I-nominated
T-compiler
labels
Oct 8, 2015
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
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). |
This comment has been minimized.
This comment has been minimized.
|
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();
} |
This comment has been minimized.
This comment has been minimized.
|
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". |
nikomatsakis
added
T-lang
and removed
T-compiler
labels
Oct 15, 2015
This comment has been minimized.
This comment has been minimized.
|
changing to T-lang because I think there is a language question here of the expected semantics of recursive autoderef. |
This comment has been minimized.
This comment has been minimized.
|
IMHO, the language should use the type that requires the least |
This comment has been minimized.
This comment has been minimized.
|
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. |
rust-highfive
added
P-low
and removed
I-nominated
labels
Oct 23, 2015
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
No, because you could always construct new types at every level using generics. |
Mark-Simulacrum
added
the
C-bug
label
Jul 22, 2017
This comment has been minimized.
This comment has been minimized.
|
Triage: not aware of any movement here. |
tomjakubowski commentedDec 4, 2014
Here's a pathological example of two types, each implementing
Derefon the other:Even though
Rc<T>implementsCloneand thus has aclonemethod, method resolution still tries to look up methods available via deref. This also happens for trying to call inherent methods on aFoodirectly (without usingRc).