Rust: Unification fails when type alias impl trait is used in non-return position

Created on 14 Sep 2019  路  10Comments  路  Source: rust-lang/rust

The following code fails to compile, but I believe this should be a supported use-case under https://github.com/rust-lang/rfcs/pull/2515 (and https://github.com/rust-lang/rust/issues/63063):

#![feature(type_alias_impl_trait)]
type X = impl Iterator<Item = u64> + Unpin;

struct Foo(X);
impl Foo {
    fn new(z: Vec<u64>) -> Self {
        Foo(z.into_iter())
    }
}

with

error[E0308]: mismatched types
  --> src/lib.rs:12:13
   |
12 |         Foo(z.into_iter())
   |             ^^^^^^^^^^^^^ expected opaque type, found struct `std::vec::IntoIter`
   |
   = note: expected type `X`
              found type `std::vec::IntoIter<u64>`

This code on the other hand works just fine with the above X:

fn foo(z: Vec<u64>) -> X {
    z.into_iter()
}

Including both Foo and foo in the same file still produces the same error, so foo does not "help" identify X.

A-inference A-typesystem C-bug F-type_alias_impl_trait T-compiler

Most helpful comment

We can start with the easier cases, and then slowly address the remaining cases. Let's get consts and statics working first.

All 10 comments

I'm going to say this is a bug... @cramertj confirm?

I think the "defining uses" for TAIT are far too restrictive at the moment. I know that @alexreg was intending to look into similar issues.

This is also becoming increasingly common for people writing their own impl Future blocks as library authors move to async fn and -> impl Future functions (e.g., tokio::TcpStream::connect), since it is now impossible to name the return type so that it can be embedded in other (custom) futures. You can hack around it with Box or by adding generic parameters, but neither of those solutions are particularly attractive.

I'm going to say this is a bug...聽@cramertj聽confirm?

Yes, the current set of defining uses is significantly reduced from what is allowed by the RFC.

@varkor @cramertj I think we need a new summary-post (issue?) detailing the defining uses. I will expand it to consts/statics for sure, but within fn bodies is more subject to debate (and trickier to implement).

RFC 2071 specified that any unification site inside the module could count as a defining use.

As long as each use uniquely defines the underlying type, it should be permitted as a defining use. That's as I understand the intention, and the one that makes the most sense (one that albeit might be trickier to implement in some cases).

@varkor Yeah, it certainly will... I think I'm going to need some advice on how to implement it inside of bodies, in this case!

We can start with the easier cases, and then slowly address the remaining cases. Let's get consts and statics working first.

I think that the error I'm dealing with is also this. Example:

#![feature(type_alias_impl_trait)]
use core::iter::Map;

trait Thing {
    type Iter: Iterator<Item = u32>;
    fn do_thing(val: u32) -> u32;
}

type DoThing<T: Thing> = impl FnOnce(u32) -> u32;

struct ThingIter<T: Thing> {
    inner: Map<T::Iter, DoThing<T>>,
}

Playground link

Was this page helpful?
0 / 5 - 0 ratings

Related issues

cuviper picture cuviper  路  3Comments

tikue picture tikue  路  3Comments

zhendongsu picture zhendongsu  路  3Comments

Robbepop picture Robbepop  路  3Comments

SharplEr picture SharplEr  路  3Comments