-
Notifications
You must be signed in to change notification settings - Fork 13.6k
Description
Given the following snippet (playground):
#![feature(existential_type)]
trait A { type B; }
mod enclosing {
struct C;
impl crate::A for C { existential type B: Copy; }
pub fn make() -> <C as crate::A>::B {
42u8 // This is a defining use.
}
}
It seems that rustc considers the scope of seeing the underlying type to be impl crate::A for C
and not enclosing
:
error: could not find defining uses
--> src/lib.rs:8:27
|
8 | impl crate::A for C { existential type B: Copy; }
| ^^^^^^^^^^^^^^^^^^^^^^^^^
The RFC states that:
Each existential type declaration must be constrained by at least one function body or const/static initializer. A body or initializer must either fully constrain or place no constraints upon a given existential type.
Existential types are similar to normal type aliases, except that their concrete type is determined from the scope in which they are defined (usually a module or a trait impl).
The latter quote suggests that the behavior seen above may be correct.
However, in a comment, the RFC also states:
impl Iterator for MyStruct { // Here we can declare an associated type whose concrete type is hidden // to other modules. // // External users only know that `Item` implements the `Debug` trait. existential type Item: Debug; ... }
This suggests (note the word module) that the current implementation is wrong and that the snippet should be allowed.
So which behavior is correct? And why? cc @cramertj @nikomatsakis @alexreg
As a final note, currently, the user has a recourse in writing:
#![feature(existential_type)]
trait A { type B; }
mod enclosing {
struct C;
existential type B: Copy;
impl crate::A for C { type B = B; }
pub fn make() -> B {
42u8
}
}