Implement existential types

This commit is contained in:
Oliver Schneider 2018-07-03 19:38:14 +02:00
parent 1c84d81873
commit 53d2ebb0ad
182 changed files with 1389 additions and 121 deletions

View file

@ -9,6 +9,7 @@
// except according to those terms.
// compile-flags: -Z parse-only
// ignore-tidy-linelength
struct Foo;
@ -16,6 +17,6 @@ impl Foo {
fn foo() {}
#[stable(feature = "rust1", since = "1.0.0")]
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or
fn main() {}

View file

@ -9,11 +9,12 @@
// except according to those terms.
// compile-flags: -Z parse-only
// ignore-tidy-linelength
struct Foo;
impl Foo {
#[stable(feature = "rust1", since = "1.0.0")]
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`, or
} //~ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`, or
fn main() {}

View file

@ -9,10 +9,11 @@
// except according to those terms.
// compile-flags: -Z parse-only
// ignore-tidy-linelength
struct S;
impl S {
static fn f() {}
}
//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `extern`, `fn`, `pub`, `type`,
//~^^ ERROR expected one of `async`, `const`, `crate`, `default`, `existential`, `extern`, `fn`, `pub`, `type`,

View file

@ -0,0 +1,113 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(existential_type)]
fn main() {
assert_eq!(foo().to_string(), "foo");
assert_eq!(bar1().to_string(), "bar1");
assert_eq!(bar2().to_string(), "bar2");
let mut x = bar1();
x = bar2();
assert_eq!(boo::boo().to_string(), "boo");
assert_eq!(my_iter(42u8).collect::<Vec<u8>>(), vec![42u8]);
}
// single definition
existential type Foo: std::fmt::Display;
fn foo() -> Foo {
"foo"
}
// two definitions
existential type Bar: std::fmt::Display;
fn bar1() -> Bar {
"bar1"
}
fn bar2() -> Bar {
"bar2"
}
// definition in submodule
existential type Boo: std::fmt::Display;
mod boo {
pub fn boo() -> super::Boo {
"boo"
}
}
existential type MyIter<T>: Iterator<Item = T>;
fn my_iter<T>(t: T) -> MyIter<T> {
std::iter::once(t)
}
fn my_iter2<T>(t: T) -> MyIter<T> {
std::iter::once(t)
}
// param names should not have an effect!
fn my_iter3<U>(u: U) -> MyIter<U> {
std::iter::once(u)
}
// param position should not have an effect!
fn my_iter4<U, V>(_: U, v: V) -> MyIter<V> {
std::iter::once(v)
}
// param names should not have an effect!
existential type MyOtherIter<T>: Iterator<Item = T>;
fn my_other_iter<U>(u: U) -> MyOtherIter<U> {
std::iter::once(u)
}
trait Trait {}
existential type GenericBound<T: Trait>: 'static;
fn generic_bound<T: Trait>(_: T) -> GenericBound<T> {
unimplemented!()
}
mod pass_through {
pub existential type Passthrough<T>: 'static;
fn define_passthrough<T: 'static>(t: T) -> Passthrough<T> {
t
}
}
fn use_passthrough(x: pass_through::Passthrough<u32>) -> pass_through::Passthrough<u32> {
x
}
existential type PartiallyDefined<T>: 'static;
// doesn't declare all PartiallyDefined for all possible `T`, but since it's the only
// function producing the value, noone can ever get a value that is problematic
fn partially_defined<T: std::fmt::Debug>(_: T) -> PartiallyDefined<T> {
4u32
}
existential type PartiallyDefined2<T>: 'static;
fn partially_defined2<T: std::fmt::Debug>(_: T) -> PartiallyDefined2<T> {
4u32
}
// fully defines PartiallyDefine2
fn partially_defined22<T>(_: T) -> PartiallyDefined2<T> {
4u32
}

View file

@ -0,0 +1,111 @@
error: defining existential type use differs from previous
--> $DIR/existential_type.rs:23:1
|
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
LL | | 42i32
LL | | }
| |_^
|
note: previous use here
--> $DIR/existential_type.rs:19:1
|
LL | / fn foo() -> Foo {
LL | | ""
LL | | }
| |_^
error[E0308]: mismatched types
--> $DIR/existential_type.rs:36:5
|
LL | fn bomp() -> boo::Boo {
| -------- expected `Boo` because of return type
LL | "" //~ ERROR mismatched types
| ^^ expected anonymized type, found reference
|
= note: expected type `Boo`
found type `&'static str`
error[E0308]: mismatched types
--> $DIR/existential_type.rs:50:23
|
LL | let _: &str = bomp(); //~ ERROR mismatched types
| ^^^^^^ expected &str, found anonymized type
|
= note: expected type `&str`
found type `Boo`
error[E0308]: mismatched types
--> $DIR/existential_type.rs:54:9
|
LL | fn bomp() -> boo::Boo {
| -------- expected `Boo` because of return type
LL | "" //~ ERROR mismatched types
| ^^ expected anonymized type, found reference
|
= note: expected type `Boo`
found type `&'static str`
error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/existential_type.rs:61:1
|
LL | existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
= help: consider adding a `where T: Trait` bound
= note: the return type of a function must have a statically known size
warning: not reporting region error due to nll
--> $DIR/existential_type.rs:78:1
|
LL | existential type WrongGeneric<T>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/existential_type.rs:93:27
|
LL | let _: &'static str = x; //~ mismatched types
| ^ expected reference, found anonymized type
|
= note: expected type `&'static str`
found type `NoReveal`
error[E0605]: non-primitive cast: `NoReveal` as `&'static str`
--> $DIR/existential_type.rs:94:13
|
LL | let _ = x as &'static str; //~ non-primitive cast
| ^^^^^^^^^^^^^^^^^
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
error: could not find defining uses
--> $DIR/existential_type.rs:28:1
|
LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: could not find defining uses
--> $DIR/existential_type.rs:32:5
|
LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: defining existential type use differs from previous
--> $DIR/existential_type.rs:74:1
|
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
LL | | Some(t).into_iter()
LL | | }
| |_^
|
note: previous use here
--> $DIR/existential_type.rs:70:1
|
LL | / fn my_iter<T>(t: T) -> MyIter<T> {
LL | | std::iter::once(t)
LL | | }
| |_^
error: aborting due to 10 previous errors
Some errors occurred: E0277, E0308, E0605.
For more information about an error, try `rustc --explain E0277`.

View file

@ -0,0 +1,95 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(existential_type)]
fn main() {}
// two definitions with different types
existential type Foo: std::fmt::Debug;
fn foo() -> Foo {
""
}
fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
42i32
}
// declared but never defined
existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses
mod boo {
// declared in module but not defined inside of it
pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses
}
fn bomp() -> boo::Boo {
"" //~ ERROR mismatched types
}
mod boo2 {
mod boo {
pub existential type Boo: ::std::fmt::Debug;
fn bomp() -> Boo {
""
}
}
// don't actually know the type here
fn bomp2() {
let _: &str = bomp(); //~ ERROR mismatched types
}
fn bomp() -> boo::Boo {
"" //~ ERROR mismatched types
}
}
// generics
trait Trait {}
existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
// no `Trait` bound
fn underconstrain<T>(_: T) -> Underconstrained<T> {
unimplemented!()
}
existential type MyIter<T>: Iterator<Item = T>;
fn my_iter<T>(t: T) -> MyIter<T> {
std::iter::once(t)
}
fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
Some(t).into_iter()
}
existential type WrongGeneric<T>: 'static;
//~^ ERROR the parameter type `T` may not live long enough
fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
t
}
// don't reveal the concrete type
existential type NoReveal: std::fmt::Debug;
fn define_no_reveal() -> NoReveal {
""
}
fn no_reveal(x: NoReveal) {
let _: &'static str = x; //~ mismatched types
let _ = x as &'static str; //~ non-primitive cast
}

View file

@ -0,0 +1,120 @@
error: defining existential type use differs from previous
--> $DIR/existential_type.rs:23:1
|
LL | / fn bar() -> Foo { //~ ERROR defining existential type use differs from previous
LL | | 42i32
LL | | }
| |_^
|
note: previous use here
--> $DIR/existential_type.rs:19:1
|
LL | / fn foo() -> Foo {
LL | | ""
LL | | }
| |_^
error[E0308]: mismatched types
--> $DIR/existential_type.rs:36:5
|
LL | fn bomp() -> boo::Boo {
| -------- expected `Boo` because of return type
LL | "" //~ ERROR mismatched types
| ^^ expected anonymized type, found reference
|
= note: expected type `Boo`
found type `&'static str`
error[E0308]: mismatched types
--> $DIR/existential_type.rs:50:23
|
LL | let _: &str = bomp(); //~ ERROR mismatched types
| ^^^^^^ expected &str, found anonymized type
|
= note: expected type `&str`
found type `Boo`
error[E0308]: mismatched types
--> $DIR/existential_type.rs:54:9
|
LL | fn bomp() -> boo::Boo {
| -------- expected `Boo` because of return type
LL | "" //~ ERROR mismatched types
| ^^ expected anonymized type, found reference
|
= note: expected type `Boo`
found type `&'static str`
error[E0277]: the trait bound `T: Trait` is not satisfied
--> $DIR/existential_type.rs:61:1
|
LL | existential type Underconstrained<T: Trait>: 'static; //~ ERROR the trait bound `T: Trait`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T`
|
= help: consider adding a `where T: Trait` bound
= note: the return type of a function must have a statically known size
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/existential_type.rs:78:1
|
LL | existential type WrongGeneric<T>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
LL | fn wrong_generic<T>(t: T) -> WrongGeneric<T> {
| - help: consider adding an explicit lifetime bound `T: 'static`...
|
note: ...so that the type `T` will meet its required lifetime bounds
--> $DIR/existential_type.rs:78:1
|
LL | existential type WrongGeneric<T>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/existential_type.rs:93:27
|
LL | let _: &'static str = x; //~ mismatched types
| ^ expected reference, found anonymized type
|
= note: expected type `&'static str`
found type `NoReveal`
error[E0605]: non-primitive cast: `NoReveal` as `&'static str`
--> $DIR/existential_type.rs:94:13
|
LL | let _ = x as &'static str; //~ non-primitive cast
| ^^^^^^^^^^^^^^^^^
|
= note: an `as` expression can only be used to convert between primitive types. Consider using the `From` trait
error: could not find defining uses
--> $DIR/existential_type.rs:28:1
|
LL | existential type Bar: std::fmt::Debug; //~ ERROR could not find defining uses
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: could not find defining uses
--> $DIR/existential_type.rs:32:5
|
LL | pub existential type Boo: ::std::fmt::Debug; //~ ERROR could not find defining uses
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: defining existential type use differs from previous
--> $DIR/existential_type.rs:74:1
|
LL | / fn my_iter2<T>(t: T) -> MyIter<T> { //~ ERROR defining existential type use differs from previous
LL | | Some(t).into_iter()
LL | | }
| |_^
|
note: previous use here
--> $DIR/existential_type.rs:70:1
|
LL | / fn my_iter<T>(t: T) -> MyIter<T> {
LL | | std::iter::once(t)
LL | | }
| |_^
error: aborting due to 11 previous errors
Some errors occurred: E0277, E0308, E0310, E0605.
For more information about an error, try `rustc --explain E0277`.

View file

@ -0,0 +1,30 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(existential_type)]
fn main() {}
existential type Underconstrained<T: std::fmt::Debug>: 'static;
//~^ ERROR `U` doesn't implement `std::fmt::Debug`
// not a defining use, because it doesn't define *all* possible generics
fn underconstrained<U>(_: U) -> Underconstrained<U> {
5u32
}
existential type Underconstrained2<T: std::fmt::Debug>: 'static;
//~^ ERROR `V` doesn't implement `std::fmt::Debug`
// not a defining use, because it doesn't define *all* possible generics
fn underconstrained2<U, V>(_: U, _: V) -> Underconstrained2<V> {
5u32
}

View file

@ -0,0 +1,23 @@
error[E0277]: `U` doesn't implement `std::fmt::Debug`
--> $DIR/existential_type2.rs:16:1
|
LL | existential type Underconstrained<T: std::fmt::Debug>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
= help: the trait `std::fmt::Debug` is not implemented for `U`
= help: consider adding a `where U: std::fmt::Debug` bound
= note: the return type of a function must have a statically known size
error[E0277]: `V` doesn't implement `std::fmt::Debug`
--> $DIR/existential_type2.rs:24:1
|
LL | existential type Underconstrained2<T: std::fmt::Debug>: 'static;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
|
= help: the trait `std::fmt::Debug` is not implemented for `V`
= 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
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,21 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(existential_type)]
fn main() {}
existential type WrongGeneric<T: 'static>: 'static;
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
v
}

View file

@ -0,0 +1,12 @@
error: type parameter `V` is part of concrete type but not used in parameter list for existential type
--> $DIR/existential_type3.rs:18:73
|
LL | fn wrong_generic<U: 'static, V: 'static>(_: U, v: V) -> WrongGeneric<U> {
| _________________________________________________________________________^
LL | | //~^ ERROR type parameter `V` is part of concrete type but not used in parameter list
LL | | v
LL | | }
| |_^
error: aborting due to previous error

View file

@ -1,4 +1,4 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@ -8,15 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-rustfix
// Point at the captured immutable outer variable
#![feature(existential_type)]
fn foo(mut f: Box<FnMut()>) {
f();
}
fn main() {
let y = true;
foo(Box::new(move || y = false) as Box<_>); //~ ERROR cannot assign to captured outer variable
fn main() {}
existential type Cmp<T>: 'static;
// not a defining use, because it doesn't define *all* possible generics
fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
5u32
}

View file

@ -0,0 +1,16 @@
error: non-defining existential type use in defining scope
--> $DIR/existential_type4.rs:19:1
|
LL | / fn cmp() -> Cmp<u32> { //~ ERROR non-defining existential type use in defining scope
LL | | 5u32
LL | | }
| |_^
|
note: used non-generic type u32 for generic parameter
--> $DIR/existential_type4.rs:16:22
|
LL | existential type Cmp<T>: 'static;
| ^
error: aborting due to previous error

View file

@ -0,0 +1,25 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Check that existential types must be ungated to use the `existential` keyword
existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable
trait Bar {
type Baa: std::fmt::Debug;
}
impl Bar for () {
existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable
}
fn main() {}

View file

@ -0,0 +1,19 @@
error[E0658]: existential types are unstable (see issue #34511)
--> $DIR/feature-gate-existential-type.rs:15:1
|
LL | existential type Foo: std::fmt::Debug; //~ ERROR existential types are unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(existential_type)] to the crate attributes to enable
error[E0658]: existential types are unstable (see issue #34511)
--> $DIR/feature-gate-existential-type.rs:22:5
|
LL | existential type Baa: std::fmt::Debug; //~ ERROR existential types are unstable
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: add #![feature(existential_type)] to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

Some files were not shown because too many files have changed in this diff Show more