-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Is this on purpose? -- Conflicting Impl Check #56804
Comments
My guess is that rustc can just figure that with |
The requirement that types be finite in length - the occurs check - is a standard rule of Hindley-Milner-style type systems that is built pretty deeply into all such type inference engines. That e.g. allows the compiler to conclude that See e.g. this code: fn main() {
let mut x = None;
x = Some(Box::new(x)); //~ ERROR mismatched types
//~| cyclic type of infinite size
} However, Rust's requirement that types have a finite size is not that deep (it might be as a requirement in order for the type to implement |
If you had a However:
|
So to sum up:
|
Makes sense, thanks! |
This was stumbled across while trying to hack around the conflicting trait implementation checker. I can intuit why it's sound, but it was surprising to me that the compiler was this "smart". I wanted to put this up to make sure we intend things to work this way.
So here's a program that is desired to work:
But the borrow implementation is rejected as conflicting:
The issue raised is that the given impl can potentially allow for
B::Metadata=Self
which completely overlaps with the blanket implementation in core. And indeed we can write a Backend implementation that does this:Although we cannot actually instantiate the type
SuperBackend<EvilBackend>
for use in ourborrow
impl, because it has infinite size! Sadly the compiler doesn't acknowledge this fact, and refuses to let us proceed.Now here's the interesting part: if we tweak our code to make the associated type a generic that we default, it compiles!
Again I can reason that this is correct, because the EvilBackend implementation is now inexpressable, leading to a compilation error:
Because
SuperBackend<EvilBackend>
is actually sugar for a type with infinite complexity:SuperBackend<EvilBackend, SuperBackend<EvilBackend, SuperBackend< .................
It's a bit surprising to me that this kind of reasoning is (apparently?) being applied now that the infinity is at the type-description level and not hidden inside a recursive associated type projection. I can imagine those are a bit different, as perhaps static members of the trait implementation could be invoked even if the implementation is unusable (due to infinite size_of)?
Anyway, just wanted to check that this is all intentional.
The text was updated successfully, but these errors were encountered: