Skip to content

Problem with type inference and impl Trait #73239

Closed
@joe-hauns

Description

@joe-hauns

Hi!
I recently experienced a bug in that probably comes from problems of the interference of type inference, impl Trait in return type position, and associated types.

This is a very strongly simplified version of what was going on in my codebase. In fact my codebase included Arc instead of SmartPointer and AsRef instead of MyAsRef, but I wanted to simplify to reproduce the problem without std.

struct SmartPointer<A>(A);

trait MyAsRef<A> {
    fn my_ref(&self) -> &A;
}

impl<A> MyAsRef<A> for SmartPointer<A> {
    fn my_ref(&self) -> &A {
        &self.0
    }
}

struct Type0Container<P>(SmartPointer<P::Type0>)
where
    P: TypeSet;

impl<P> Type0Container<P>
where
    P: TypeSet,
{
    // fn item(&self) -> &SmartPointer<P::Type0> { // << compiles
    fn item(&self) -> &impl MyAsRef<P::Type0> {    // << does not compile
        &self.0
    }
}

trait TypeSet {
    type Type0;
}

struct TypeSetImpl;
struct Type0Impl;

impl TypeSet for TypeSetImpl {
    type Type0 = Type0Impl;
}

fn main() {
    let proc: Type0Container<TypeSetImpl> = Type0Container(SmartPointer(Type0Impl)); 
    let _: &Type0Impl = proc.item().my_ref();
}

I expected to see this happen:
The compiler should be able to infer that <TypeSetImpl as TypeSet>::Type0 = Type0Impl and compile the program.

Instead, this happened:
The compiler failed with this error message:

   Compiling lala v0.1.0 (/path/to/lala)
error[E0308]: mismatched types
  --> src/main.rs:41:25
   |
41 |     let _: &Type0Impl = proc.item().my_ref();
   |            ----------   ^^^^^^^^^^^^^^^^^^^^ expected struct `Type0Impl`, found associated type
   |            |
   |            expected due to this
   |
   = note: expected reference `&Type0Impl`
              found reference `&<TypeSetImpl as TypeSet>::Type0`
   = help: consider constraining the associated type `<TypeSetImpl as TypeSet>::Type0` to `Type0Impl`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

As noted in the comments in the code snipped changing the one line using impl Trait in return type position enables the compiler to build the program.
I'm not entirely sure if this is a bug or if I expecting type inference to be stronger as it is or if the code I wrote is indeed not correct, so sorry if that is the case.

Meta

rustc --version --verbose:

rustc 1.46.0-nightly (449e8eaa2 2020-06-10)
binary: rustc
commit-hash: 449e8eaa286e407c9cd8cac655b77998fd53db6b
commit-date: 2020-06-10
host: x86_64-apple-darwin
release: 1.46.0-nightly
LLVM version: 10.0
None

<backtrace>

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-associated-itemsArea: Associated items (types, constants & functions)A-impl-traitArea: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch.A-lazy-normalizationArea: Lazy normalization (tracking issue: #60471)A-trait-systemArea: Trait systemC-bugCategory: This is a bug.T-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions