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

Require a trait in the bounds of existential types #60409

Merged
merged 5 commits into from
May 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use syntax::ptr::P;
use syntax::visit::{self, Visitor};
use syntax::{span_err, struct_span_err, walk_list};
use syntax_ext::proc_macro_decls::is_proc_macro_attr;
use syntax_pos::Span;
use syntax_pos::{Span, MultiSpan};
use errors::Applicability;
use log::debug;

Expand Down Expand Up @@ -679,6 +679,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
"unions cannot have zero fields");
}
}
ItemKind::Existential(ref bounds, _) => {
if !bounds.iter()
.any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) {
let msp = MultiSpan::from_spans(bounds.iter()
.map(|bound| bound.span()).collect());
self.err_handler().span_err(msp, "at least one trait must be specified");
}
}
_ => {}
}

Expand Down
4 changes: 2 additions & 2 deletions src/test/run-pass/existential_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,14 @@ fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
}

trait Trait {}
existential type GenericBound<'a, T: Trait>: 'a;
existential type GenericBound<'a, T: Trait>: Sized + 'a;

fn generic_bound<'a, T: Trait + 'a>(t: T) -> GenericBound<'a, T> {
t
}

mod pass_through {
pub existential type Passthrough<T>: 'static;
pub existential type Passthrough<T>: Sized + 'static;

fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
t
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/existential_types/existential-types-with-no-traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#![feature(existential_type)]

existential type Foo: 'static;
//~^ ERROR: at least one trait must be specified

fn foo() -> Foo {
"foo"
}

fn bar() -> impl 'static { //~ ERROR: at least one trait must be specified
"foo"
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: at least one trait must be specified
--> $DIR/existential-types-with-no-traits.rs:3:23
|
LL | existential type Foo: 'static;
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
| ^^^^^^^

error: at least one trait must be specified
--> $DIR/existential-types-with-no-traits.rs:10:13
|
LL | fn bar() -> impl 'static {
| ^^^^^^^^^^^^

error: aborting due to 2 previous errors

2 changes: 2 additions & 0 deletions src/test/ui/existential_types/generic_nondefining_use.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ fn main() {}

existential type Cmp<T>: 'static;
//~^ ERROR could not find defining uses
//~^^ ERROR: at least one trait must be specified


// not a defining use, because it doesn't define *all* possible generics
fn cmp() -> Cmp<u32> { //~ ERROR defining existential type use does not fully define
Expand Down
10 changes: 8 additions & 2 deletions src/test/ui/existential_types/generic_nondefining_use.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
error: at least one trait must be specified
--> $DIR/generic_nondefining_use.rs:5:26
|
LL | existential type Cmp<T>: 'static;
| ^^^^^^^

error: defining existential type use does not fully define existential type
--> $DIR/generic_nondefining_use.rs:9:1
--> $DIR/generic_nondefining_use.rs:11:1
|
LL | / fn cmp() -> Cmp<u32> {
LL | | 5u32
Expand All @@ -12,5 +18,5 @@ error: could not find defining uses
LL | existential type Cmp<T>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

1 change: 1 addition & 0 deletions src/test/ui/existential_types/generic_not_used.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
fn main() {}

existential type WrongGeneric<T: 'static>: 'static;
//~^ ERROR: at least one trait must be specified

fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
//~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
Expand Down
10 changes: 8 additions & 2 deletions src/test/ui/existential_types/generic_not_used.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
error: at least one trait must be specified
--> $DIR/generic_not_used.rs:5:44
|
LL | existential type WrongGeneric<T: 'static>: 'static;
| ^^^^^^^

error: type parameter `V` is part of concrete type but not used in parameter list for existential type
--> $DIR/generic_not_used.rs:7:73
--> $DIR/generic_not_used.rs:8:73
|
LL | fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
| _________________________________________________________________________^
Expand All @@ -8,5 +14,5 @@ LL | | v
LL | | }
| |_^

error: aborting due to previous error
error: aborting due to 2 previous errors

Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ fn main() {

existential type WrongGeneric<T>: 'static;
//~^ ERROR the parameter type `T` may not live long enough
//~^^ ERROR: at least one trait must be specified

fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
t
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error: at least one trait must be specified
--> $DIR/generic_type_does_not_live_long_enough.rs:9:35
|
LL | existential type WrongGeneric<T>: 'static;
| ^^^^^^^

error[E0308]: mismatched types
--> $DIR/generic_type_does_not_live_long_enough.rs:6:18
|
Expand All @@ -22,7 +28,7 @@ note: ...so that the type `T` will meet its required lifetime bounds
LL | existential type WrongGeneric<T>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 2 previous errors
error: aborting due to 3 previous errors

Some errors have detailed explanations: E0308, E0310.
For more information about an error, try `rustc --explain E0308`.
1 change: 1 addition & 0 deletions src/test/ui/existential_types/generic_underconstrained.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ fn main() {}

trait Trait {}
existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
//~^ ERROR: at least one trait must be specified

// no `Trait` bound
fn underconstrain<T>(_: T) -> Underconstrained<T> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
error: at least one trait must be specified
--> $DIR/generic_underconstrained.rs:6:46
|
LL | existential type Underconstrained<T: Trait>: 'static;
| ^^^^^^^

error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/generic_underconstrained.rs:6:1
|
Expand All @@ -7,6 +13,6 @@ LL | existential type Underconstrained<T: Trait>: 'static;
= help: consider adding a `where T: Trait` bound
= note: the return type of a function must have a statically known size

error: aborting due to previous error
error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.
2 changes: 2 additions & 0 deletions src/test/ui/existential_types/generic_underconstrained2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ fn main() {}

existential type Underconstrained<T: std::fmt::Debug>: 'static;
//~^ ERROR `U` doesn't implement `std::fmt::Debug`
//~^^ ERROR: at least one trait must be specified

// not a defining use, because it doesn't define *all* possible generics
fn underconstrained<U>(_: U) -> Underconstrained<U> {
Expand All @@ -12,6 +13,7 @@ fn underconstrained<U>(_: U) -> Underconstrained<U> {

existential type Underconstrained2<T: std::fmt::Debug>: 'static;
//~^ ERROR `V` doesn't implement `std::fmt::Debug`
//~^^ ERROR: at least one trait must be specified

// not a defining use, because it doesn't define *all* possible generics
fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
Expand Down
16 changes: 14 additions & 2 deletions src/test/ui/existential_types/generic_underconstrained2.stderr
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
error: at least one trait must be specified
--> $DIR/generic_underconstrained2.rs:5:56
|
LL | existential type Underconstrained<T: std::fmt::Debug>: 'static;
| ^^^^^^^

error: at least one trait must be specified
--> $DIR/generic_underconstrained2.rs:14:57
|
LL | existential type Underconstrained2<T: std::fmt::Debug>: 'static;
| ^^^^^^^

error[E0277]: `U` doesn't implement `std::fmt::Debug`
--> $DIR/generic_underconstrained2.rs:5:1
|
Expand All @@ -9,7 +21,7 @@ LL | existential type Underconstrained<T: std::fmt::Debug>: 'static;
= note: the return type of a function must have a statically known size

error[E0277]: `V` doesn't implement `std::fmt::Debug`
--> $DIR/generic_underconstrained2.rs:13:1
--> $DIR/generic_underconstrained2.rs:14:1
|
LL | existential type Underconstrained2<T: std::fmt::Debug>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
Expand All @@ -18,6 +30,6 @@ LL | existential type Underconstrained2<T: std::fmt::Debug>: 'static;
= help: consider adding a `where V: std::fmt::Debug` bound
= note: the return type of a function must have a statically known size

error: aborting due to 2 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0277`.
5 changes: 2 additions & 3 deletions src/test/ui/existential_types/unused_generic_param.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
// compile-pass
#![feature(existential_type)]

fn main() {
}

// test that unused generic parameters are ok
existential type PartiallyDefined<T>: 'static;
//~^ ERROR: at least one trait must be specified

fn partially_defined<T: std::fmt::Debug>(_: T) -> PartiallyDefined<T> {
4u32
}

// test that unused generic parameters are ok
existential type PartiallyDefined2<T>: 'static;
//~^ ERROR: at least one trait must be specified

fn partially_defined2<T: std::fmt::Debug>(_: T) -> PartiallyDefined2<T> {
4u32
Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/existential_types/unused_generic_param.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: at least one trait must be specified
--> $DIR/unused_generic_param.rs:6:39
|
LL | existential type PartiallyDefined<T>: 'static;
| ^^^^^^^

error: at least one trait must be specified
--> $DIR/unused_generic_param.rs:13:40
|
LL | existential type PartiallyDefined2<T>: 'static;
| ^^^^^^^

error: aborting due to 2 previous errors