Description
The existence of an implementation for Add<Container<A>> for X where X: Add<A>
causes a compiler error under certain circumstances for expressions of the form X + X
. Here's an example:
use std::ops::Add;
pub struct Container<T>(Vec<T>);
impl<A, B> Add<Container<A>> for f32
where
f32: Add<A, Output = B>,
{
type Output = B;
fn add(self, _rhs: Container<A>) -> B {
unimplemented!()
}
}
fn doesnt_compile<'a, V>(a: V) -> f32
where
V: Into<Container<&'a f32>>,
{
let a: Container<&'a f32> = a.into();
0f32 + 1f32
}
I expected this to compile without errors. Instead, I receive the following error message (abbreviated below):
error[E0275]: overflow evaluating the requirement `f32: Add<Container<_>>`
--> src/main.rs:20:10
|
20 | 0f32 + 1f32
| ^
|
= help: consider adding a `#![recursion_limit="256"]` attribute to your crate (`playground`)
= note: required because of the requirements on the impl of `Add<Container<Container<_>>>` for `f32`
= note: required because of the requirements on the impl of `Add<Container<Container<Container<_>>>>` for `f32`
= note: required because of the requirements on the impl of `Add<Container<Container<Container<Container<_>>>>>` for `f32`
= note: required because of the requirements on the impl of `Add<Container<Container<Container<Container<Container<_>>>>>>` for `f32`
= note: required because of the requirements on the impl of `Add<Container<Container<Container<Container<Container<Container<_>>>>>>>` for `f32`
...
Observe that even though the addition is between two f32
literals, the error message indicates that the compiler is trying to apply the impl involving Container
.
Note that it still fails to compile if I replace f32
with a custom struct.
To help diagnose the issue, it's helpful to note that replacing the doesnt_compile
function with any of the following similar functions causes the example to compile without errors:
fn compiles1<'a, V>(a: V) -> f32
where
V: Into<Container<&'a f32>>,
{
let a: Container<&'a f32> = a.into();
1f32
}
fn compiles2<'a>(a: Container<&'a f32>) -> f32 {
0f32 + 1f32
}
fn compiles3<V>(a: V) -> f32
where
V: Into<Container<f32>>,
{
let a: Container<f32> = a.into();
0f32 + 1f32
}
We first observed the issue in a more complicated case in the ndarray
crate. (See the discussion here.) This bug report is a simplified example. Edit: Interestingly, in the more complicated case, we observed differing error messages between different platforms.
Meta
Stable (1.48.0), Beta (1.50.0-beta.1, 2020-12-29), and Nightly (1.51.0-nightly, 2020-12-29) all produce a compilation error (tested with the Rust Playground).
On my machine, rustc --version --verbose
:
rustc 1.48.0 (7eac88abb 2020-11-16)
binary: rustc
commit-hash: 7eac88abb2e57e752f3302f02be5f3ce3d7adfb4
commit-date: 2020-11-16
host: x86_64-unknown-linux-gnu
release: 1.48.0
LLVM version: 11.0