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

Cannot use associated type as type of associated const #46969

Closed
kennytm opened this issue Dec 23, 2017 · 4 comments · Fixed by #116865
Closed

Cannot use associated type as type of associated const #46969

kennytm opened this issue Dec 23, 2017 · 4 comments · Fixed by #116865
Labels
A-associated-items Area: Associated items (types, constants & functions) A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. D-papercut Diagnostics: An error or lint that needs small tweaks. P-low Low priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@kennytm
Copy link
Member

kennytm commented Dec 23, 2017

Repro:

trait O {
    type M;
}
trait U<A: O> {
    const N: A::M;
}
impl<D> O for D {
    type M = u8;
}
impl<C: O> U<C> for u16 {
    const N: C::M = 4;
}

This caused E0277 "the trait bound is not satisfied" error:

error[E0277]: the trait bound `C: std::marker::Sized` is not satisfied
  --> src/main.rs:11:5
   |
11 |     const N: C::M = 4;
   |     ^^^^^^^^^^^^^^^^^^ `C` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `C`
   = help: consider adding a `where C: std::marker::Sized` bound
   = note: required because of the requirements on the impl of `O` for `C`

The error doesn't make sense because C is obviously Sized. It seems the associated const type is evaluated before the generic bounds are added, causing this error.

Changing both A::M and C::M to u8 makes the error go away.


Reproducible on all 3 versions on playground (1.23.0, 1.24.0-beta, 1.25.0-nightly).

@kennytm kennytm added A-associated-items Area: Associated items (types, constants & functions) C-bug Category: This is a bug. labels Dec 23, 2017
@kennytm kennytm added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-diagnostics Area: Messages for errors, warnings, and lints labels Jan 23, 2018
@oberien
Copy link
Contributor

oberien commented Mar 10, 2018

This exact issue just occured to @CryZe and me when trying to use associated constants to create a constant struct in a library with user-provided data (without const fns) (actual use case: playground). A minimized examples is this (playground):

use std::marker::PhantomData;

trait Const {
    type T;
    const VAL: Self::T;
}

struct MakeTuple<U>(PhantomData<U>);
impl<U: Const + Sized> Const for MakeTuple<U> {
    type T = (U::T, U::T);
    const VAL: Self::T = (U::VAL, U::VAL);
}

Error:

error[E0277]: the trait bound `U: std::marker::Sized` is not satisfied
  --> src/main.rs:11:5
   |
11 |     const VAL: Self::T = (U::VAL, U::VAL);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `U`
   = help: consider adding a `where U: std::marker::Sized` bound
   = note: required because of the requirements on the impl of `Const` for `MakeTuple<U>`

error[E0277]: the trait bound `U: Const` is not satisfied
  --> src/main.rs:11:5
   |
11 |     const VAL: Self::T = (U::VAL, U::VAL);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Const` is not implemented for `U`
   |
   = help: consider adding a `where U: Const` bound
   = note: required because of the requirements on the impl of `Const` for `MakeTuple<U>`

The interesting thing is that even though both bounds are specified, the compiler doesn't seem to take them into account.

Edit: The issue is not using a trait with an associated type and const as generic bound. Instead the problem is implementing a trait with an associated type and const in general: playground

@bgeron
Copy link

bgeron commented May 19, 2018

I ran into the same problem. It's also in 1.26 stable.

Here's a further minimized example (play):

trait EmptyTrait {}

trait Const {
    type T;
    const VAL: Self::T;
}

impl<U: EmptyTrait + std::marker::Sized> Const for U
{
    type T = u32;
    const VAL: u32 = 5;
}

We can also use the type parameter in the trait rather than the type (play):

trait EmptyTrait {}

trait Const<U> {
    type T;
    const VAL: Self::T;
}

impl<U: EmptyTrait + Sized> Const<U> for () {
    type T = u32;
    const VAL: Self::T = 5;
}

Both code fragments give an error saying that in the blanket impl, Rust cannot figure out that U implements EmptyTrait and Sized:

error[E0277]: the trait bound `U: std::marker::Sized` is not satisfied
  --> src/lib.rs:12:5
   |
12 |     const VAL: Self::T = 5;
   |     ^^^^^^^^^^^^^^^^^^^^^^^ `U` does not have a constant size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `U`
   = help: consider adding a `where U: std::marker::Sized` bound
   = note: required because of the requirements on the impl of `Const<U>` for `()`

error[E0277]: the trait bound `U: EmptyTrait` is not satisfied
  --> src/lib.rs:12:5
   |
12 |     const VAL: Self::T = 5;
   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `EmptyTrait` is not implemented for `U`
   |
   = help: consider adding a `where U: EmptyTrait` bound
   = note: required because of the requirements on the impl of `Const<U>` for `()`

Note that in both cases, if you remove the EmptyTrait constraint on the quantified type U, the error about EmptyTrait goes away! This is very strange. However, like in #50824, the Sized error message stays.

The problem goes away if you declare the type of VAL in Const to be u32, rather than some type that is computed potentially based on parameters.

I'm not familiar with the compiler internals, but my hypothesis is that associated types and constants depending on a type parameter are not evaluated properly in the constant expression evaluator. In this case, it's associated types that do not reduce well: const VAL: Self::T = 5; forces Rust to do some fancy type of computation at compile time in order to type check, but there's a bug in the code for such computations.

I feel there are a couple of different issues in the same spirit:

@CAD97
Copy link
Contributor

CAD97 commented Sep 2, 2018

Copying over my minimal example from #53908 as another data point (playground):

use std::marker::PhantomData;

pub trait FromPest: Sized {
    type Rule;
    const RULE: Self::Rule;
}

impl<T> FromPest for PhantomData<T>
where
    T: FromPest,
{
    type Rule = T::Rule;
    const RULE: T::Rule = T::RULE;
}

Here I've added a Sized supertrait to my trait to get rid of the Sized issue but it still can't determine the required trait implementation (of my trait in this case) to make this work.

CAD97 added a commit to pest-parser/ast that referenced this issue Sep 2, 2018
cc rust-lang/rust#46969
The reason that the PhantomData approach doesn't work
Not that the generic EOI does either
CAD97 added a commit to pest-parser/ast that referenced this issue Sep 11, 2018
Bonus: fixes PestDeconstructor::discard
to _actually_ skip the drop

This does reduce runtime guarantees,
as it doesn't only drop EOI,
but hey, it makes it work.

With the fix for rust-lang/rust#46969, we should
be able to use PhantomData to mark ignored pairs.
@estebank
Copy link
Contributor

estebank commented Apr 29, 2019

All of these cases now compile, except for the original report, which has a type error:

error[E0308]: mismatched types
  --> src/lib.rs:11:21
   |
11 |     const N: C::M = 4u8;
   |                     ^^^ expected associated type, found u8
   |
   = note: expected type `<C as O>::M`
              found type `u8`

Current output:

error[E0308]: mismatched types
  --> src/lib.rs:11:21
   |
11 |     const N: C::M = 4u8;
   |                     ^^^ expected associated type, found u8
   |
   = note: expected type `<C as O>::M`
              found type `u8`
   = note: consider constraining the associated type `<C as O>::M` to `u8` or calling a method that returns `<C as O>::M`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

The correct code would be

trait O {
    type M;
}
trait U<A: O> {
    const N: A::M;
}
impl<D> O for D {
    type M = u8;
}
impl<C> U<C> for u16 where C: O<M=u32>{
    const N: C::M = 4;
}

The outstanding work would be providing a suggestion explaining what "consider constraining the associated type <C as O>::M to u8" means. This will be hard to do given the different cases that need to be accounted for, for the case above you need to move the C: O constraint to where, for example (although that's not needed, just nicer stylistically).

@estebank estebank added A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` P-low Low priority and removed C-bug Category: This is a bug. labels Sep 26, 2019
@estebank estebank added the D-papercut Diagnostics: An error or lint that needs small tweaks. label Dec 13, 2019
@JohnTitor JohnTitor added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Feb 16, 2020
estebank added a commit to estebank/rust that referenced this issue Oct 17, 2023
aliemjay added a commit to aliemjay/rust that referenced this issue Oct 18, 2023
…rrors

Suggest constraining assoc types in more cases

Fix rust-lang#46969.

```
error[E0308]: mismatched types
  --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21
   |
LL |     const N: C::M = 4u8;
   |                     ^^^ expected associated type, found `u8`
   |
   = note: expected associated type `<C as O>::M`
                         found type `u8`
help: consider constraining the associated type `<C as O>::M` to `u8`
   |
LL | impl<C: O<M = u8>> U<C> for u16 {
   |          ++++++++

```
@bors bors closed this as completed in dee86bf Oct 18, 2023
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Oct 18, 2023
Rollup merge of rust-lang#116865 - estebank:issue-46969, r=compiler-errors

Suggest constraining assoc types in more cases

Fix rust-lang#46969.

```
error[E0308]: mismatched types
  --> $DIR/suggest-contraining-assoc-type-because-of-assoc-const.rs:12:21
   |
LL |     const N: C::M = 4u8;
   |                     ^^^ expected associated type, found `u8`
   |
   = note: expected associated type `<C as O>::M`
                         found type `u8`
help: consider constraining the associated type `<C as O>::M` to `u8`
   |
LL | impl<C: O<M = u8>> U<C> for u16 {
   |          ++++++++

```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-diagnostics Area: Messages for errors, warnings, and lints A-suggestion-diagnostics Area: Suggestions generated by the compiler applied by `cargo fix` C-enhancement Category: An issue proposing an enhancement or a PR with one. D-papercut Diagnostics: An error or lint that needs small tweaks. P-low Low priority T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants