Error: Recursion limit reached while automatically dereferencing T
I wonder if this is normal or is it a bug:
struct A<T> (T);
impl<T> Add<A<T>, A<T>> for A<T>
where T: Add<T, T> + Deref<T> + Copy {
fn add(&self, &A(b): &A<T>) -> A<T> {
let A(a) = *self;
A(a.add(&b))
}
}
raises this error:
<anon>:7:11: 7:12 error: reached the recursion limit while auto-dereferencing T [E0055]
<anon>:7 A(a.add(&b))
when replaced a.add(&b)
with, it a+b
compiles without errors
a+b
should n't be just sugar for a.add(&b)
?
source to share
Short version: The T
implementation Deref<T>
doesn't make sense, and so the differences in the way method calls and operator calls with respect to dereferencing the left side blow things up, because it's a + b
not quite the same as a.add(&b)
.
Long version:
Operator +
and Add.add
operate differently in relation to the use of links.
The operator+
takes both operands by reference. a + b
for operands of the corresponding types A
and B
requires that there be an implementation Add<B, C>
for A
and create a value of the type C
. As indicated A
and B
taken from the link; he makes these references himself, silently; there is no guesswork. This is how they work:
let a = 1i;
let b = a + a; // this one works
let c = a + &a; // mismatched types: expected `int`, found `&int` (expected int, found &-ptr)
let d = &a + a; // binary operation `+` cannot be applied to type `&int`
let e = &a + &a; // binary operation `+` cannot be applied to type `&int`
No dereferencing happens in any of them, and so the dodgy requirement T: Deref<T>
won't blow anything up.
Add.add
takes both values โโby reference. Like a normal function call, it has the ability to automatically dereference and reference the left side when needed. While the right side as a method argument is passed as is, the left side is dereferenced as much as possible to find all possible methods that might be implied add
. This is usually ok and it will do what you want, but in this case it won't, because T
(from which type A
) implements Deref<T>
. So dereferencing does it T
. And then T
, realizing Deref<T>
, acting out T
. Moreover, it T
implements Deref<T>
and therefore divides into T
. It continues to do this until it reaches the recursion limit. Really,T
the implementation Deref<T>
just doesn't make sense.
For comparison, here are some examples of how method invocation works:
let a = 1i;
let b = a.add(a); // mismatched types: expected `&int`, found `int` (expected &-ptr, found int)
let c = a.add(&a); // this one works (a reference to the LHS is taken automatically)
let d = (&a).add(a); // mismatched types: expected `&int`, found `int` (expected &-ptr, found int)
let e = (&a).add(&a); // this one works (LHS is dereferenced and then rereferenced)
source to share