Auto merge of #86264 - crlf0710:trait_upcasting_part1, r=nikomatsakis
Trait upcasting coercion (part1) This revives the first part of earlier PR #60900 . It's not very clear to me which parts of that pr was design decisions, so i decide to cut it into pieces and land them incrementally. This allows more eyes on the details. This is the first part, it adds feature gates, adds feature gates tests, and implemented the unsize conversion part. (I hope i have dealt with the `ExistentialTraitRef` values correctly...) The next part will be implementing the pointer casting.
This commit is contained in:
commit
7069a8c2b7
@ -683,6 +683,10 @@ declare_features! (
|
||||
/// Allows the `?` operator in const contexts.
|
||||
(active, const_try, "1.56.0", Some(74935), None),
|
||||
|
||||
/// Allows upcasting trait objects via supertraits.
|
||||
/// Trait upcasting is casting, e.g., `dyn Foo -> dyn Bar` where `Foo: Bar`.
|
||||
(incomplete, trait_upcasting, "1.56.0", Some(65991), None),
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// feature-group-end: actual feature gates
|
||||
// -------------------------------------------------------------------------
|
||||
|
@ -1270,6 +1270,7 @@ symbols! {
|
||||
trace_macros,
|
||||
track_caller,
|
||||
trait_alias,
|
||||
trait_upcasting,
|
||||
transmute,
|
||||
transparent,
|
||||
transparent_enums,
|
||||
|
@ -693,22 +693,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
let may_apply = match (source.kind(), target.kind()) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
(&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => {
|
||||
// Upcasts permit two things:
|
||||
//
|
||||
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
|
||||
//
|
||||
// Note that neither of these changes requires any
|
||||
// change at runtime. Eventually this will be
|
||||
// generalized.
|
||||
//
|
||||
// We always upcast when we can because of reason
|
||||
// #2 (region bounds).
|
||||
data_a.principal_def_id() == data_b.principal_def_id()
|
||||
&& data_b
|
||||
.auto_traits()
|
||||
// All of a's auto traits need to be in b's auto traits.
|
||||
.all(|b| data_a.auto_traits().any(|a| a == b))
|
||||
// See `confirm_builtin_unsize_candidate` for more info.
|
||||
let auto_traits_compatible = data_b
|
||||
.auto_traits()
|
||||
// All of a's auto traits need to be in b's auto traits.
|
||||
.all(|b| data_a.auto_traits().any(|a| a == b));
|
||||
auto_traits_compatible
|
||||
}
|
||||
|
||||
// `T` -> `Trait`
|
||||
|
@ -703,10 +703,56 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
match (source.kind(), target.kind()) {
|
||||
// Trait+Kx+'a -> Trait+Ky+'b (upcasts).
|
||||
(&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => {
|
||||
// See `assemble_candidates_for_unsizing` for more info.
|
||||
let iter = data_a
|
||||
.principal()
|
||||
.map(|b| b.map_bound(ty::ExistentialPredicate::Trait))
|
||||
// Upcast coercions permit several things:
|
||||
//
|
||||
// 1. Dropping auto traits, e.g., `Foo + Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g., `Foo + 'a` to `Foo + 'b` if `'a: 'b`
|
||||
// 3. Tightening trait to its super traits, eg. `Foo` to `Bar` if `Foo: Bar`
|
||||
//
|
||||
// Note that neither of the first two of these changes requires any
|
||||
// change at runtime. The third needs to change pointer metadata at runtime.
|
||||
//
|
||||
// We always perform upcasting coercions when we can because of reason
|
||||
// #2 (region bounds).
|
||||
|
||||
// We already checked the compatiblity of auto traits within `assemble_candidates_for_unsizing`.
|
||||
|
||||
let principal_a = data_a.principal();
|
||||
let principal_def_id_b = data_b.principal_def_id();
|
||||
|
||||
let existential_predicate = if let Some(principal_a) = principal_a {
|
||||
let source_trait_ref = principal_a.with_self_ty(tcx, source);
|
||||
let target_trait_did = principal_def_id_b.ok_or_else(|| Unimplemented)?;
|
||||
let upcast_idx = util::supertraits(tcx, source_trait_ref)
|
||||
.position(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
|
||||
.ok_or_else(|| Unimplemented)?;
|
||||
// FIXME(crlf0710): This is less than ideal, for example,
|
||||
// if the trait is defined as `trait Foo: Bar<u32> + Bar<i32>`,
|
||||
// the coercion from Box<Foo> to Box<dyn Bar<_>> is actually ambiguous.
|
||||
// We currently make this coercion fail for now.
|
||||
//
|
||||
// see #65991 for more information.
|
||||
if util::supertraits(tcx, source_trait_ref)
|
||||
.skip(upcast_idx + 1)
|
||||
.any(|upcast_trait_ref| upcast_trait_ref.def_id() == target_trait_did)
|
||||
{
|
||||
return Err(Unimplemented);
|
||||
}
|
||||
let target_trait_ref =
|
||||
util::supertraits(tcx, source_trait_ref).nth(upcast_idx).unwrap();
|
||||
let existential_predicate = target_trait_ref.map_bound(|trait_ref| {
|
||||
ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
|
||||
tcx, trait_ref,
|
||||
))
|
||||
});
|
||||
Some(existential_predicate)
|
||||
} else if principal_def_id_b.is_none() {
|
||||
None
|
||||
} else {
|
||||
return Err(Unimplemented);
|
||||
};
|
||||
|
||||
let iter = existential_predicate
|
||||
.into_iter()
|
||||
.chain(
|
||||
data_a
|
||||
|
@ -576,6 +576,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
)];
|
||||
|
||||
let mut has_unsized_tuple_coercion = false;
|
||||
let mut has_trait_upcasting_coercion = false;
|
||||
|
||||
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
|
||||
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
|
||||
@ -590,7 +591,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
if traits.contains(&trait_pred.def_id()) =>
|
||||
{
|
||||
if unsize_did == trait_pred.def_id() {
|
||||
let self_ty = trait_pred.self_ty();
|
||||
let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty();
|
||||
if let (ty::Dynamic(ref data_a, ..), ty::Dynamic(ref data_b, ..)) =
|
||||
(self_ty.kind(), unsize_ty.kind())
|
||||
{
|
||||
if data_a.principal_def_id() != data_b.principal_def_id() {
|
||||
debug!("coerce_unsized: found trait upcasting coercion");
|
||||
has_trait_upcasting_coercion = true;
|
||||
}
|
||||
}
|
||||
if let ty::Tuple(..) = unsize_ty.kind() {
|
||||
debug!("coerce_unsized: found unsized tuple coercion");
|
||||
has_unsized_tuple_coercion = true;
|
||||
@ -666,6 +676,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
if has_trait_upcasting_coercion && !self.tcx().features().trait_upcasting {
|
||||
feature_err(
|
||||
&self.tcx.sess.parse_sess,
|
||||
sym::trait_upcasting,
|
||||
self.cause.span,
|
||||
"trait upcasting coercion is experimental",
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
Ok(coercion)
|
||||
}
|
||||
|
||||
|
13
src/test/ui/feature-gates/feature-gate-trait_upcasting.rs
Normal file
13
src/test/ui/feature-gates/feature-gate-trait_upcasting.rs
Normal file
@ -0,0 +1,13 @@
|
||||
trait Foo {}
|
||||
|
||||
trait Bar: Foo {}
|
||||
|
||||
impl Foo for () {}
|
||||
|
||||
impl Bar for () {}
|
||||
|
||||
fn main() {
|
||||
let bar: &dyn Bar = &();
|
||||
let foo: &dyn Foo = bar;
|
||||
//~^ ERROR trait upcasting coercion is experimental [E0658]
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0658]: trait upcasting coercion is experimental
|
||||
--> $DIR/feature-gate-trait_upcasting.rs:11:25
|
||||
|
|
||||
LL | let foo: &dyn Foo = bar;
|
||||
| ^^^
|
||||
|
|
||||
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
|
||||
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
@ -1,10 +1,10 @@
|
||||
#![feature(box_syntax)]
|
||||
|
||||
struct Test {
|
||||
func: Box<dyn FnMut() + 'static>
|
||||
func: Box<dyn FnMut() + 'static>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
|
||||
let test = box Test { func: closure }; //~ ERROR mismatched types
|
||||
let test = box Test { func: closure }; //~ ERROR trait upcasting coercion is experimental [E0658]
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
error[E0308]: mismatched types
|
||||
error[E0658]: trait upcasting coercion is experimental
|
||||
--> $DIR/issue-11515.rs:9:33
|
||||
|
|
||||
LL | let test = box Test { func: closure };
|
||||
| ^^^^^^^ expected trait `FnMut`, found trait `Fn`
|
||||
| ^^^^^^^
|
||||
|
|
||||
= note: expected struct `Box<(dyn FnMut() + 'static)>`
|
||||
found struct `Box<(dyn Fn() + 'static)>`
|
||||
= note: see issue #65991 <https://github.com/rust-lang/rust/issues/65991> for more information
|
||||
= help: add `#![feature(trait_upcasting)]` to the crate attributes to enable
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
@ -0,0 +1,13 @@
|
||||
// run-pass
|
||||
#![feature(box_syntax, trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
struct Test {
|
||||
func: Box<dyn FnMut() + 'static>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
|
||||
let mut test = box Test { func: closure };
|
||||
(test.func)();
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
// check-fail
|
||||
#![feature(trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Bar<T> {
|
||||
fn bar(&self, _: T) {}
|
||||
}
|
||||
|
||||
trait Foo : Bar<i32> + Bar<u32> {
|
||||
fn foo(&self, _: ()) {}
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
impl Bar<i32> for S {}
|
||||
impl Bar<u32> for S {}
|
||||
impl Foo for S {}
|
||||
|
||||
fn main() {
|
||||
let s: &dyn Foo = &S;
|
||||
let t: &dyn Bar<_> = s; //~ ERROR mismatched types
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/multiple-occurence-ambiguousity.rs:21:26
|
||||
|
|
||||
LL | let t: &dyn Bar<_> = s;
|
||||
| ----------- ^ expected trait `Bar`, found trait `Foo`
|
||||
| |
|
||||
| expected due to this
|
||||
|
|
||||
= note: expected reference `&dyn Bar<_>`
|
||||
found reference `&dyn Foo`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
33
src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
Normal file
33
src/test/ui/traits/trait-upcasting/type-checking-test-1.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![feature(trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo: Bar<i32> + Bar<u32> {}
|
||||
trait Bar<T> {
|
||||
fn bar(&self) -> Option<T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn test_specific(x: &dyn Foo) {
|
||||
let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<i32>` is not satisfied
|
||||
let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
}
|
||||
|
||||
fn test_unknown_version(x: &dyn Foo) {
|
||||
let _ = x as &dyn Bar<_>; // Ambiguous
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied
|
||||
}
|
||||
|
||||
fn test_infer_version(x: &dyn Foo) {
|
||||
let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
let _: Option<u32> = a.bar();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,80 @@
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<i32>`
|
||||
--> $DIR/type-checking-test-1.rs:12:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
|
||||
--> $DIR/type-checking-test-1.rs:15:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<i32>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:12:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<i32>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<i32>`
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:15:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<_>`
|
||||
--> $DIR/type-checking-test-1.rs:21:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<_>; // Ambiguous
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:21:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<_>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar<u32>`
|
||||
--> $DIR/type-checking-test-1.rs:27:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let a = &x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo: Bar<u32>` is not satisfied
|
||||
--> $DIR/type-checking-test-1.rs:27:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||
|
||||
error: aborting due to 8 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0605.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
34
src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
Normal file
34
src/test/ui/traits/trait-upcasting/type-checking-test-2.rs
Normal file
@ -0,0 +1,34 @@
|
||||
#![feature(trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<T>: Bar<i32> + Bar<T> {}
|
||||
trait Bar<T> {
|
||||
fn bar(&self) -> Option<T> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn test_specific(x: &dyn Foo<i32>) {
|
||||
let _ = x as &dyn Bar<i32>; // OK
|
||||
}
|
||||
|
||||
fn test_specific2(x: &dyn Foo<u32>) {
|
||||
let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
|
||||
}
|
||||
|
||||
fn test_specific3(x: &dyn Foo<i32>) {
|
||||
let _ = x as &dyn Bar<u32>; // Error
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
|
||||
}
|
||||
|
||||
fn test_infer_arg(x: &dyn Foo<u32>) {
|
||||
let a = x as &dyn Bar<_>; // Ambiguous
|
||||
//~^ ERROR non-primitive cast
|
||||
//~^^ ERROR the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
|
||||
let _ = a.bar();
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,61 @@
|
||||
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<i32>`
|
||||
--> $DIR/type-checking-test-2.rs:16:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<i32>` is not satisfied
|
||||
--> $DIR/type-checking-test-2.rs:16:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<i32>; // FIXME: OK, eventually
|
||||
| ^ the trait `Bar<i32>` is not implemented for `&dyn Foo<u32>`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<i32>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo<i32>` as `&dyn Bar<u32>`
|
||||
--> $DIR/type-checking-test-2.rs:22:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // Error
|
||||
| ^^^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let _ = &x as &dyn Bar<u32>; // Error
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied
|
||||
--> $DIR/type-checking-test-2.rs:22:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<u32>; // Error
|
||||
| ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<u32>`
|
||||
|
||||
error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>`
|
||||
--> $DIR/type-checking-test-2.rs:28:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^^^^^^^^^^^^^^^^ invalid cast
|
||||
|
|
||||
help: consider borrowing the value
|
||||
|
|
||||
LL | let a = &x as &dyn Bar<_>; // Ambiguous
|
||||
| ^
|
||||
|
||||
error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied
|
||||
--> $DIR/type-checking-test-2.rs:28:13
|
||||
|
|
||||
LL | let a = x as &dyn Bar<_>; // Ambiguous
|
||||
| ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>`
|
||||
|
|
||||
= note: required for the cast to the object type `dyn Bar<_>`
|
||||
|
||||
error: aborting due to 6 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0277, E0605.
|
||||
For more information about an error, try `rustc --explain E0277`.
|
22
src/test/ui/traits/trait-upcasting/type-checking-test-3.rs
Normal file
22
src/test/ui/traits/trait-upcasting/type-checking-test-3.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// ignore-compare-mode-nll
|
||||
#![feature(trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<'a>: Bar<'a> {}
|
||||
trait Bar<'a> {}
|
||||
|
||||
fn test_correct(x: &dyn Foo<'static>) {
|
||||
let _ = x as &dyn Bar<'static>;
|
||||
}
|
||||
|
||||
fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
|
||||
let _ = x as &dyn Bar<'a>; // Error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_wrong2<'a>(x: &dyn Foo<'a>) {
|
||||
let _ = x as &dyn Bar<'static>; // Error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,33 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-checking-test-3.rs:13:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<'a>; // Error
|
||||
| ^ lifetime mismatch
|
||||
|
|
||||
= note: expected trait object `dyn Bar<'a>`
|
||||
found trait object `dyn Bar<'static>`
|
||||
note: the lifetime `'a` as defined on the function body at 12:16...
|
||||
--> $DIR/type-checking-test-3.rs:12:16
|
||||
|
|
||||
LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
|
||||
| ^^
|
||||
= note: ...does not necessarily outlive the static lifetime
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-checking-test-3.rs:18:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<'static>; // Error
|
||||
| ^ lifetime mismatch
|
||||
|
|
||||
= note: expected trait object `dyn Bar<'static>`
|
||||
found trait object `dyn Bar<'a>`
|
||||
note: the lifetime `'a` as defined on the function body at 17:16...
|
||||
--> $DIR/type-checking-test-3.rs:17:16
|
||||
|
|
||||
LL | fn test_wrong2<'a>(x: &dyn Foo<'a>) {
|
||||
| ^^
|
||||
= note: ...does not necessarily outlive the static lifetime
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0308`.
|
32
src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
Normal file
32
src/test/ui/traits/trait-upcasting/type-checking-test-4.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// ignore-compare-mode-nll
|
||||
#![feature(trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo<'a>: Bar<'a, 'a> {}
|
||||
trait Bar<'a, 'b> {
|
||||
fn get_b(&self) -> Option<&'a u32> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn test_correct(x: &dyn Foo<'static>) {
|
||||
let _ = x as &dyn Bar<'static, 'static>;
|
||||
}
|
||||
|
||||
fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
|
||||
let _ = x as &dyn Bar<'static, 'a>; // Error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
|
||||
let _ = x as &dyn Bar<'a, 'static>; // Error
|
||||
//~^ ERROR mismatched types
|
||||
}
|
||||
|
||||
fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
|
||||
let y = x as &dyn Bar<'_, '_>;
|
||||
//~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
|
||||
y.get_b() // ERROR
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,47 @@
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-checking-test-4.rs:17:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<'static, 'a>; // Error
|
||||
| ^ lifetime mismatch
|
||||
|
|
||||
= note: expected trait object `dyn Bar<'static, 'a>`
|
||||
found trait object `dyn Bar<'static, 'static>`
|
||||
note: the lifetime `'a` as defined on the function body at 16:16...
|
||||
--> $DIR/type-checking-test-4.rs:16:16
|
||||
|
|
||||
LL | fn test_wrong1<'a>(x: &dyn Foo<'static>, y: &'a u32) {
|
||||
| ^^
|
||||
= note: ...does not necessarily outlive the static lifetime
|
||||
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/type-checking-test-4.rs:22:13
|
||||
|
|
||||
LL | let _ = x as &dyn Bar<'a, 'static>; // Error
|
||||
| ^ lifetime mismatch
|
||||
|
|
||||
= note: expected trait object `dyn Bar<'a, 'static>`
|
||||
found trait object `dyn Bar<'static, 'static>`
|
||||
note: the lifetime `'a` as defined on the function body at 21:16...
|
||||
--> $DIR/type-checking-test-4.rs:21:16
|
||||
|
|
||||
LL | fn test_wrong2<'a>(x: &dyn Foo<'static>, y: &'a u32) {
|
||||
| ^^
|
||||
= note: ...does not necessarily outlive the static lifetime
|
||||
|
||||
error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
|
||||
--> $DIR/type-checking-test-4.rs:27:27
|
||||
|
|
||||
LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> {
|
||||
| ------------ this data with lifetime `'a`...
|
||||
LL | let y = x as &dyn Bar<'_, '_>;
|
||||
| - ^^
|
||||
| |
|
||||
| ...is captured here...
|
||||
LL |
|
||||
LL | y.get_b() // ERROR
|
||||
| --------- ...and is required to live as long as `'static` here
|
||||
|
||||
error: aborting due to 3 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0308, E0759.
|
||||
For more information about an error, try `rustc --explain E0308`.
|
Loading…
x
Reference in New Issue
Block a user