Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infering default generic arguments through traits #50107

Closed
Ekleog opened this issue Apr 20, 2018 · 3 comments
Closed

Infering default generic arguments through traits #50107

Ekleog opened this issue Apr 20, 2018 · 3 comments
Labels
A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Ekleog
Copy link

Ekleog commented Apr 20, 2018

I've recently come across an issue of type inference that can be summed up like this:

trait Trait {
    type A;
    type B;
}

enum Foo<A, B> { A(A), B(B) }
impl<A, B> Trait for Foo<A, B> { type A = A; type B = B; }

enum Many<A, B, T1 = Foo<A, B>, T2 = Foo<A, B>, T3 = Foo<A, B>>
where T1: Trait<A = A, B = B>,
      T2: Trait<A = A, B = B>,
      T3: Trait<A = A, B = B>,
{
    M1(T1), M2(T2), M3(T3)
}

fn main() {
    let x = match 3 {
        1 => Many::M1(Foo::A(3u8)),
        _ => Many::M2(Foo::B(3u16)),
    };
}

returns

error[E0282]: type annotations needed
  --> src/main.rs:19:14
   |
18 |     let x = match 3 {
   |         - consider giving `x` a type
19 |         1 => Many::M1(Foo::A(3u8)),
   |              ^^^^^^^^ cannot infer type for `T3`

(playground)

I would have thought rustc could be able to infer the type for T3 as Foo<u8, u16>, through this procedure:

  1. the match arms return Many<'a, 'b, 't1, 't2, 't3> with 't1 = Foo<u8, 'b1> and 't2 = Foo<'a2, u16>
  2. The where clause says 't1: Trait<'a, 'b>, and we only have 't1: Trait<u8, 'b1>, so we can unify and get 'a = u8 and 'b = 'b1
  3. The where clause also says 't2: Trait<'a, 'b>, and we only have 't2: Trait<'a2, u16>, so we can unify and get 'a = 'a2 and 'b = u16
  4. So currently we are at the match arms return Many<u8, u16, Foo<u8, u16>, Foo<u8, u16>, 't3>
  5. Applying the default for 't3 gives 't3 = Foo<u8, u16>, which is what I'm hoping for

In the meantime, would you happen to know of a way to do what I'm trying to do? Ideally it'd be a variadic enum, but not being able to figure out a way to do it I just decided to have a cap on the number of variants, and hit this bug. If this could not be a solution based on auto-generating a rust file for all possible numbers of variants it'd be even better, but…

@Ekleog
Copy link
Author

Ekleog commented Apr 20, 2018

By the way, here is a maybe simpler example, using Void instead of Foo<A, B>, so that type inference wouldn't even have to use trait definitions to infer the types represented by A and B, that fails in the same way:

trait Trait {
    type A;
    type B;
}

enum Void {}
impl Trait for Void { type A = Void; type B = Void; }

enum Foo<A, B> { A(A), B(B) }
impl<A, B> Trait for Foo<A, B> { type A = A; type B = B; }

enum Many<A, B, T1 = Void, T2 = Void, T3 = Void>
where T1: Trait<A = A, B = B>,
      T2: Trait<A = A, B = B>,
      T3: Trait<A = A, B = B>,
{
    M1(T1), M2(T2), M3(T3)
}

fn main() {
    let x = match 3 {
        1 => Many::M1(Foo::A(3u8)),
        _ => Many::M2(Foo::B(3u16)),
    };
}

@Mark-Simulacrum Mark-Simulacrum added the A-inference Area: Type inference label May 29, 2018
@XAMPPRocky XAMPPRocky added C-enhancement Category: An issue proposing an enhancement or a PR with one. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Sep 25, 2018
@Spoonbender
Copy link

Triage: no change

@estebank
Copy link
Contributor

Current output:

error[E0282]: type annotations needed
  --> f71.rs:19:14
   |
19 |         1 => Many::M1(Foo::A(3u8)),
   |              ^^^^^^^^ cannot infer type of the type parameter `T3` declared on the enum `Many`
   |
help: consider specifying the generic arguments
   |
19 |         1 => Many::<u8, u16, Foo<u8, u16>, Foo<u8, u16>, T3>::M1(Foo::A(3u8)),
   |                  +++++++++++++++++++++++++++++++++++++++++++

With #114811:

error[E0283]: type annotations needed
  --> f71.rs:19:14
   |
19 |         1 => Many::M1(Foo::A(3u8)),
   |              ^^^^^^^^ cannot infer type of the type parameter `T3` declared on the enum `Many`
   |
   = note: cannot satisfy `_: Trait`
   = help: the trait `Trait` is implemented for `Foo<A, B>`
note: required by a bound in `Many::M1`
  --> f71.rs:12:11
   |
12 |       T3: Trait<A = A, B = B>,
   |           ^^^^^^^^^^^^^^^^^^^ required by this bound in `Many::M1`
13 | {
14 |     M1(T1), M2(T2), M3(T3)
   |     -- required by a bound in this tuple variant
help: consider specifying the generic arguments
   |
19 |         1 => Many::<u8, u16, Foo<u8, u16>, Foo<u8, u16>, T3>::M1(Foo::A(3u8)),
   |                  +++++++++++++++++++++++++++++++++++++++++++

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants