Skip to content

Operator impl causes compilation error for an expression involving the operator with a different pair of types #80542

Open
@jturner314

Description

@jturner314

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
}

(playground)

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.fixed-by-next-solverFixed by the next-generation trait solver, `-Znext-solver`.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions