5

Consider the following code:

pub trait Trait { type Type; const CONST: Self::Type; } impl<T> Trait for T { type Type = u8; const CONST: u8 = 42; } 

My (incorrect?) understanding of Rust is that this code should work and that all Sized types should now implement Trait and have an associated type (Type = u8) and const (CONST = 42). Unsized types shouldn't implement this trait since impl<T> implicitly assumes T to be Sized.

However, when I try to compile the code I get the error message:

error[E0277]: the size for value values of type `T` cannot be known at compilation time --> src/main.rs:8:3 | 8 | const CONST: u8 = 42; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `T` = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types--sized> = help: consider adding a `where T: std::marker::Sized` bound = note: required because of the requirements on the impl of `Trait` for `T` 

My questions:

  • Why does Rust think that T isn't Sized here? Explicitly stating T: Sized doesn't help.
  • Let's pretend T isn't Sized. Why does Rust care whether T is sized or not here? Nothing depends on it, as far as I can tell (the associated type and const aren't related to T). Changing the code to T: ?Sized works, so clearly T being unsized isn't actually problematic.
5
  • 4
    This seems to be a bug. There is an open issue for it. Commented Jun 29, 2018 at 6:38
  • Did you mean to write impl<T: Sized> Trait for T? (This doesn't solve the problem but matches your problem description more) Commented Jun 29, 2018 at 7:49
  • 2
    @Tim T: Sized is redundant: All type parameters have an implicit bound of Sized.. Commented Jun 29, 2018 at 7:52
  • @kazemakase: Thanks! If you post that as an answer I'll accept it. Commented Jun 29, 2018 at 13:20
  • @Cornstalks "It's a bug" hardly makes for a good answer... but apparently it is the only one there is :( Commented Jun 29, 2018 at 14:19

1 Answer 1

2

According to this GitHub issue, this appears to be a known bug that has been around at least since Rust 1.23 (longer, I suspect).

It is not clear what is causing the problem and when/if it will be fixed. There is only a rather vague hypothesis:

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.

There are a few ways to work around the issue:

  1. Specifying a concrete type in the trait:

    pub trait Trait { // type Type; // no longer used const CONST: u8; } 
  2. Opting T out of Sized:

    impl<T: ?Sized> Trait for T { type Type = u8; const CONST: u8 = 42; } 
  3. Use a function instead of a constant (credit goes to @PeterHall):

    pub trait Trait { type Type; fn const_val() -> Self::Type; } impl<T> Trait for T { type Type = u8; fn const_val() -> Self::Type { 42 } } 
Sign up to request clarification or add additional context in comments.

2 Comments

As a workaround, can't you just use a function in the trait instead of a const? It should get inlined to the same thing.
@PeterHall You are right of course. Thank you for pointing out that oversight.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.