diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 1ec9a0518b809..638330c904d75 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -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 // ------------------------------------------------------------------------- diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 295e53aba3542..1ac489f600a40 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1270,6 +1270,7 @@ symbols! { trace_macros, track_caller, trait_alias, + trait_upcasting, transmute, transparent, transparent_enums, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 752f6a8debc9e..c7bf1f2a94319 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -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` diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index f8297ee3a0718..0c2099593a261 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -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 + Bar`, + // the coercion from Box to Box> 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 diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index ba76b9c8dd5a0..a83b39a110834 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -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) } diff --git a/src/test/ui/feature-gates/feature-gate-trait_upcasting.rs b/src/test/ui/feature-gates/feature-gate-trait_upcasting.rs new file mode 100644 index 0000000000000..e4102f1cfa75d --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-trait_upcasting.rs @@ -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] +} diff --git a/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr b/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr new file mode 100644 index 0000000000000..bc13a5d7d7b46 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-trait_upcasting.stderr @@ -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 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`. diff --git a/src/test/ui/issues/issue-11515.rs b/src/test/ui/issues/issue-11515.rs index a7671b9282a99..2072f9c47e2a6 100644 --- a/src/test/ui/issues/issue-11515.rs +++ b/src/test/ui/issues/issue-11515.rs @@ -1,10 +1,10 @@ #![feature(box_syntax)] struct Test { - func: Box + func: Box, } fn main() { let closure: Box = Box::new(|| ()); - let test = box Test { func: closure }; //~ ERROR mismatched types + let test = box Test { func: closure }; //~ ERROR trait upcasting coercion is experimental [E0658] } diff --git a/src/test/ui/issues/issue-11515.stderr b/src/test/ui/issues/issue-11515.stderr index 7935615ad7e50..a70e7c416bc0f 100644 --- a/src/test/ui/issues/issue-11515.stderr +++ b/src/test/ui/issues/issue-11515.stderr @@ -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 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`. diff --git a/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs new file mode 100644 index 0000000000000..277d9eabe4fb2 --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs @@ -0,0 +1,13 @@ +// run-pass +#![feature(box_syntax, trait_upcasting)] +#![allow(incomplete_features)] + +struct Test { + func: Box, +} + +fn main() { + let closure: Box = Box::new(|| ()); + let mut test = box Test { func: closure }; + (test.func)(); +} diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs new file mode 100644 index 0000000000000..6986ad6217240 --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.rs @@ -0,0 +1,22 @@ +// check-fail +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Bar { + fn bar(&self, _: T) {} +} + +trait Foo : Bar + Bar { + fn foo(&self, _: ()) {} +} + +struct S; + +impl Bar for S {} +impl Bar for S {} +impl Foo for S {} + +fn main() { + let s: &dyn Foo = &S; + let t: &dyn Bar<_> = s; //~ ERROR mismatched types +} diff --git a/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr new file mode 100644 index 0000000000000..e9670ad7def4d --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/multiple-occurence-ambiguousity.stderr @@ -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`. diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs new file mode 100644 index 0000000000000..1a0e5072843fe --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.rs @@ -0,0 +1,33 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: Bar + Bar {} +trait Bar { + fn bar(&self) -> Option { + None + } +} + +fn test_specific(x: &dyn Foo) { + let _ = x as &dyn Bar; // FIXME: OK, eventually + //~^ ERROR non-primitive cast + //~^^ ERROR the trait bound `&dyn Foo: Bar` is not satisfied + let _ = x as &dyn Bar; // FIXME: OK, eventually + //~^ ERROR non-primitive cast + //~^^ ERROR the trait bound `&dyn Foo: Bar` 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` is not satisfied + let _: Option = a.bar(); +} + +fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr new file mode 100644 index 0000000000000..6aaa8a4a90437 --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-1.stderr @@ -0,0 +1,80 @@ +error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` + --> $DIR/type-checking-test-1.rs:12:13 + | +LL | let _ = x as &dyn Bar; // FIXME: OK, eventually + | ^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | let _ = &x as &dyn Bar; // FIXME: OK, eventually + | ^ + +error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` + --> $DIR/type-checking-test-1.rs:15:13 + | +LL | let _ = x as &dyn Bar; // FIXME: OK, eventually + | ^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | let _ = &x as &dyn Bar; // FIXME: OK, eventually + | ^ + +error[E0277]: the trait bound `&dyn Foo: Bar` is not satisfied + --> $DIR/type-checking-test-1.rs:12:13 + | +LL | let _ = x as &dyn Bar; // FIXME: OK, eventually + | ^ the trait `Bar` is not implemented for `&dyn Foo` + | + = note: required for the cast to the object type `dyn Bar` + +error[E0277]: the trait bound `&dyn Foo: Bar` is not satisfied + --> $DIR/type-checking-test-1.rs:15:13 + | +LL | let _ = x as &dyn Bar; // FIXME: OK, eventually + | ^ 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<_>` + --> $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` + --> $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` is not satisfied + --> $DIR/type-checking-test-1.rs:27:13 + | +LL | let a = x as &dyn Bar<_>; // FIXME: OK, eventually + | ^ the trait `Bar` is not implemented for `&dyn Foo` + | + = note: required for the cast to the object type `dyn Bar` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0277, E0605. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs new file mode 100644 index 0000000000000..326df74211eff --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.rs @@ -0,0 +1,34 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: Bar + Bar {} +trait Bar { + fn bar(&self) -> Option { + None + } +} + +fn test_specific(x: &dyn Foo) { + let _ = x as &dyn Bar; // OK +} + +fn test_specific2(x: &dyn Foo) { + let _ = x as &dyn Bar; // FIXME: OK, eventually + //~^ ERROR non-primitive cast + //~^^ ERROR the trait bound `&dyn Foo: Bar` is not satisfied +} + +fn test_specific3(x: &dyn Foo) { + let _ = x as &dyn Bar; // Error + //~^ ERROR non-primitive cast + //~^^ ERROR the trait bound `&dyn Foo: Bar` is not satisfied +} + +fn test_infer_arg(x: &dyn Foo) { + let a = x as &dyn Bar<_>; // Ambiguous + //~^ ERROR non-primitive cast + //~^^ ERROR the trait bound `&dyn Foo: Bar<_>` is not satisfied + let _ = a.bar(); +} + +fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr new file mode 100644 index 0000000000000..a38f8a146043e --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -0,0 +1,61 @@ +error[E0605]: non-primitive cast: `&dyn Foo` as `&dyn Bar` + --> $DIR/type-checking-test-2.rs:16:13 + | +LL | let _ = x as &dyn Bar; // FIXME: OK, eventually + | ^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | let _ = &x as &dyn Bar; // FIXME: OK, eventually + | ^ + +error[E0277]: the trait bound `&dyn Foo: Bar` is not satisfied + --> $DIR/type-checking-test-2.rs:16:13 + | +LL | let _ = x as &dyn Bar; // FIXME: OK, eventually + | ^ 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` + --> $DIR/type-checking-test-2.rs:22:13 + | +LL | let _ = x as &dyn Bar; // Error + | ^^^^^^^^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | let _ = &x as &dyn Bar; // Error + | ^ + +error[E0277]: the trait bound `&dyn Foo: Bar` is not satisfied + --> $DIR/type-checking-test-2.rs:22:13 + | +LL | let _ = x as &dyn Bar; // Error + | ^ 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<_>` + --> $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: 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` + | + = 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`. diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs new file mode 100644 index 0000000000000..49c24e404dc6e --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.rs @@ -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() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr new file mode 100644 index 0000000000000..593ee0a34300a --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-3.stderr @@ -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`. diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs new file mode 100644 index 0000000000000..9b27fd46f7acd --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs @@ -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() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr new file mode 100644 index 0000000000000..811e524eda78b --- /dev/null +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -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`.