Evaluation overflow with specialization feature
The current nightly compiler gives the error "overflow evaluating requirement" when a type is used as a trait with a default impl. For example:
#![feature(specialization)]
fn main() {
println!("{}", <(usize) as TypeString>::type_string());
}
trait TypeString {
fn type_string() -> &'static str;
}
default impl<T> TypeString for T {
fn type_string() -> &'static str {
"unknown type"
}
}
impl TypeString for () {
fn type_string() -> &'static str {
"()"
}
}
...gives the following error:
error[E0275]: overflow evaluating the requirement `usize: TypeString`
--> src/main.rs:4:20
|
4 | println!("{}", <(usize) as TypeString>::type_string());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: required by `TypeString::type_string`
--> src/main.rs:8:5
|
8 | fn type_string() -> &'static str;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Note that if we change <(usize) as TypeString>::type_string() to <() as TypeString>::type_string() - () has a specialized impl - it compiles and runs correctly.
Note if you move the
defaultkeyword to the fn itself, it works. Not sure if this is intentional or not.vitalyd at 2018-02-24 20:26:17
Oh, odd. And it looks like it's allowed to have the
defaultkeyword on both theimpland thefn, although that doesn't fix this bug. That's pretty confusing. Does anyone know if they do different things, or are they just synonyms?Joshua Liebow-Feeser at 2018-02-24 21:08:58
implwithdefaulted items anddefault implare different as described in rust-lang/rfcs#1210. However, unfortunately, they had been implemented uniformly before #45404.Masaki Hara at 2018-02-25 02:59:07
Am I misreading the RFC? It looks like it doesn't define
default implat all:Why mark
defaulton items rather than the entire impl? Again, this is largely about granularity; it's useful to be able to pin down part of an impl while leaving others open for specialization. Furthermore, while this RFC doesn't propose to do it, we could easily add a shorthand later on in whichdefault impl Trait for Typeis sugar for addingdefaultto all items in the impl.Joshua Liebow-Feeser at 2018-02-25 23:19:26
Strange. The other parts of the RFC mention
default implwith the clear example:// the `default` qualifier here means (1) not all items are impled // and (2) those that are can be further specialized default impl<T: Clone, Rhs> Add<Rhs> for T { fn add_assign(&mut self, rhs: R) { let tmp = self.clone() + rhs; *self = tmp; } }To me the RFC seems to be self-contradicting a bit.
Anyway, from the example above, we can see that
default impls with partial implementation are allowed. The remaining point is whetherdefault impls with full implementation are used to resolve trait obligation. I think it is good to treat them uniformly with partialdefault impls, as @nikomatsakis says.Masaki Hara at 2018-02-26 14:08:33
#![feature(specialization)] trait Type { const FOO: bool; } default impl<T> Type for T { const FOO: bool = false; } fn main() { <u8 as Type>::FOO; }Another example.
Aidan Hobson Sayers at 2018-03-12 18:36:01
Any progress on this? I ran into it again. Anybody I should consult on this? I'd like to help debug since this is blocking me on some work.
EDIT: Not blocked anymore; I figured out a workaround.
Joshua Liebow-Feeser at 2019-03-02 06:33:59
Would you mind sharing that workaround @joshlf?
Joel Höner at 2019-03-06 12:14:39
It's unfortunately not a general workaround; I just figured out a way to avoid using this feature entirely so it wasn't a problem.
Joshua Liebow-Feeser at 2019-03-06 17:59:40
Anyone know, where to start fixing this? The workaround worked for my use case, but it's a little strange and unexpected. Just adding a message to the error about this issue could help some.
Avi Dessauer at 2020-06-03 00:49:27
lol i keep forgetting about this and running into it.
estk at 2022-09-23 04:55:01