Skip to content

Commit

Permalink
Rollup merge of rust-lang#60409 - JohnTitor:error-for-existential-typ…
Browse files Browse the repository at this point in the history
…e, r=oli-obk

Require a trait in the bounds of existential types

Fixes rust-lang#53090

r? @oli-obk
  • Loading branch information
Centril authored May 3, 2019
2 parents bfa22cf + 748d978 commit f622861
Show file tree
Hide file tree
Showing 16 changed files with 106 additions and 14 deletions.
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;
| ^^^^^^^

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

0 comments on commit f622861

Please sign in to comment.