diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1827e42368f..a4ba1a5c9bf 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -236,7 +236,7 @@ enum ImplTraitContext { ReturnPositionOpaqueTy { /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn, origin: hir::OpaqueTyOrigin, - in_trait: bool, + fn_kind: FnDeclKind, }, /// Impl trait in type aliases. TypeAliasesOpaqueTy { in_assoc_ty: bool }, @@ -312,7 +312,7 @@ impl std::fmt::Display for ImplTraitPosition { } } -#[derive(Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum FnDeclKind { Fn, Inherent, @@ -1401,13 +1401,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { TyKind::ImplTrait(def_node_id, bounds) => { let span = t.span; match itctx { - ImplTraitContext::ReturnPositionOpaqueTy { origin, in_trait } => self + ImplTraitContext::ReturnPositionOpaqueTy { origin, fn_kind } => self .lower_opaque_impl_trait( span, *origin, *def_node_id, bounds, - *in_trait, + Some(*fn_kind), itctx, ), &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self @@ -1416,7 +1416,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, *def_node_id, bounds, - false, + None, itctx, ), ImplTraitContext::Universal => { @@ -1523,7 +1523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { origin: hir::OpaqueTyOrigin, opaque_ty_node_id: NodeId, bounds: &GenericBounds, - in_trait: bool, + fn_kind: Option, itctx: &ImplTraitContext, ) -> hir::TyKind<'hir> { // Make sure we know that some funky desugaring has been going on here. @@ -1540,10 +1540,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { Vec::new() } hir::OpaqueTyOrigin::FnReturn(..) => { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` - // example, we only need to duplicate lifetimes that appear in the - // bounds, since those are the only ones that are captured by the opaque. - lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + if let FnDeclKind::Impl | FnDeclKind::Trait = + fn_kind.expect("expected RPITs to be lowered with a FnKind") + { + // return-position impl trait in trait was decided to capture all + // in-scope lifetimes, which we collect for all opaques during resolution. + self.resolver + .take_extra_lifetime_params(opaque_ty_node_id) + .into_iter() + .map(|(ident, id, _)| Lifetime { id, ident }) + .collect() + } else { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` + // example, we only need to duplicate lifetimes that appear in the + // bounds, since those are the only ones that are captured by the opaque. + lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + } } hir::OpaqueTyOrigin::AsyncFn(..) => { unreachable!("should be using `lower_async_fn_ret_ty`") @@ -1554,7 +1566,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.lower_opaque_inner( opaque_ty_node_id, origin, - in_trait, + matches!(fn_kind, Some(FnDeclKind::Trait)), captured_lifetimes_to_duplicate, span, opaque_ty_span, @@ -1802,12 +1814,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } let fn_def_id = self.local_def_id(fn_node_id); - self.lower_async_fn_ret_ty( - &decl.output, - fn_def_id, - ret_id, - matches!(kind, FnDeclKind::Trait), - ) + self.lower_async_fn_ret_ty(&decl.output, fn_def_id, ret_id, kind) } else { match &decl.output { FnRetTy::Ty(ty) => { @@ -1815,7 +1822,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fn_def_id = self.local_def_id(fn_node_id); ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait: matches!(kind, FnDeclKind::Trait), + fn_kind: kind, } } else { let position = match kind { @@ -1883,7 +1890,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { output: &FnRetTy, fn_def_id: LocalDefId, opaque_ty_node_id: NodeId, - in_trait: bool, + fn_kind: FnDeclKind, ) -> hir::FnRetTy<'hir> { let span = self.lower_span(output.span()); let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::Async, span, None); @@ -1898,7 +1905,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let opaque_ty_ref = self.lower_opaque_inner( opaque_ty_node_id, hir::OpaqueTyOrigin::AsyncFn(fn_def_id), - in_trait, + matches!(fn_kind, FnDeclKind::Trait), captured_lifetimes, span, opaque_ty_span, @@ -1906,7 +1913,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let future_bound = this.lower_async_fn_output_type_to_future_bound( output, span, - if in_trait && !this.tcx.features().return_position_impl_trait_in_trait { + if let FnDeclKind::Trait = fn_kind + && !this.tcx.features().return_position_impl_trait_in_trait + { ImplTraitContext::FeatureGated( ImplTraitPosition::TraitReturn, sym::return_position_impl_trait_in_trait, @@ -1914,7 +1923,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { ImplTraitContext::ReturnPositionOpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id), - in_trait, + fn_kind, } }, ); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 168cc16bb36..e745ef1ec07 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -813,6 +813,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing), + rustc_attr!(TEST, rustc_variance_of_opaques, Normal, template!(Word), WarnFollowing), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."), WarnFollowing), rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing), diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs index d57d05d7605..d98dc0e6b83 100644 --- a/compiler/rustc_hir_analysis/src/variance/test.rs +++ b/compiler/rustc_hir_analysis/src/variance/test.rs @@ -1,9 +1,24 @@ +use rustc_hir::def::DefKind; +use rustc_hir::def_id::CRATE_DEF_ID; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; use crate::errors; pub fn test_variance(tcx: TyCtxt<'_>) { + if tcx.has_attr(CRATE_DEF_ID, sym::rustc_variance_of_opaques) { + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) { + let variances_of = tcx.variances_of(id.owner_id); + + tcx.sess.emit_err(errors::VariancesOf { + span: tcx.def_span(id.owner_id), + variances_of: format!("{variances_of:?}"), + }); + } + } + } + // For unit testing: check for a special "rustc_variance" // attribute and report an error with various results if found. for id in tcx.hir().items() { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 22d084c8e0b..500004269c9 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -772,9 +772,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, self.r.record_partial_res(ty.id, PartialRes::new(res)); visit::walk_ty(self, ty) } - TyKind::ImplTrait(..) => { + TyKind::ImplTrait(node_id, _) => { let candidates = self.lifetime_elision_candidates.take(); visit::walk_ty(self, ty); + self.record_lifetime_params_for_impl_trait(*node_id); self.lifetime_elision_candidates = candidates; } TyKind::TraitObject(bounds, ..) => { @@ -909,8 +910,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, &sig.decl.output, ); - if let Some((async_node_id, span)) = sig.header.asyncness.opt_return_id() { - this.record_lifetime_params_for_impl_trait(async_node_id, span); + if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() { + this.record_lifetime_params_for_impl_trait(async_node_id); } }, ); @@ -951,8 +952,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, &declaration.output, ); - if let Some((async_node_id, span)) = async_node_id { - this.record_lifetime_params_for_impl_trait(async_node_id, span); + if let Some((async_node_id, _)) = async_node_id { + this.record_lifetime_params_for_impl_trait(async_node_id); } }, ); @@ -4367,7 +4368,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { /// We include all lifetime parameters, either named or "Fresh". /// The order of those parameters does not matter, as long as it is /// deterministic. - fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId, span: Span) { + fn record_lifetime_params_for_impl_trait(&mut self, impl_trait_node_id: NodeId) { let mut extra_lifetime_params = vec![]; for rib in self.lifetime_ribs.iter().rev() { @@ -4380,14 +4381,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { extra_lifetime_params.extend(earlier_fresh); } } - LifetimeRibKind::Generics { .. } => {} - _ => { - // We are in a function definition. We should only find `Generics` - // and `AnonymousCreateParameter` inside the innermost `Item`. - span_bug!(span, "unexpected rib kind: {:?}", rib.kind) - } + _ => {} } } + self.r.extra_lifetime_params_map.insert(impl_trait_node_id, extra_lifetime_params); } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9d4f49f9453..656deebb5d0 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1366,6 +1366,7 @@ symbols! { rustc_trivial_field_reads, rustc_unsafe_specialization_marker, rustc_variance, + rustc_variance_of_opaques, rustdoc, rustdoc_internals, rustdoc_missing_doc_code_examples, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 88d03003309..8a24f96743a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -548,7 +548,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.span, "GATs in trait object shouldn't have been considered", ); - return Err(SelectionError::Unimplemented); + return Err(SelectionError::TraitNotObjectSafe(trait_predicate.trait_ref.def_id)); } // This maybe belongs in wf, but that can't (doesn't) handle diff --git a/tests/ui/impl-trait/in-trait/object-safety.rs b/tests/ui/impl-trait/in-trait/object-safety.rs index dd35b9a2d8a..9a231e59b09 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.rs +++ b/tests/ui/impl-trait/in-trait/object-safety.rs @@ -19,4 +19,5 @@ fn main() { //~| ERROR the trait `Foo` cannot be made into an object let s = i.baz(); //~^ ERROR the trait `Foo` cannot be made into an object + //~| ERROR the trait `Foo` cannot be made into an object } diff --git a/tests/ui/impl-trait/in-trait/object-safety.stderr b/tests/ui/impl-trait/in-trait/object-safety.stderr index 4a3b3b11465..0170dc5d0fc 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.stderr @@ -13,6 +13,21 @@ LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait +error[E0038]: the trait `Foo` cannot be made into an object + --> $DIR/object-safety.rs:20:15 + | +LL | let s = i.baz(); + | ^^^ `Foo` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit + --> $DIR/object-safety.rs:7:22 + | +LL | trait Foo { + | --- this trait cannot be made into an object... +LL | fn baz(&self) -> impl Debug; + | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type + = help: consider moving `baz` to another trait + error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/object-safety.rs:20:13 | @@ -44,6 +59,6 @@ LL | fn baz(&self) -> impl Debug; = help: consider moving `baz` to another trait = note: required for the cast from `Box` to `Box` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr new file mode 100644 index 00000000000..186580f5756 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.failure.stderr @@ -0,0 +1,14 @@ +error[E0623]: lifetime mismatch + --> $DIR/signature-mismatch.rs:77:10 + | +LL | &'a self, + | -------- this parameter and the return type are declared with different lifetimes... +... +LL | ) -> impl Future> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | ...but data from `buff` is returned here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0623`. diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.rs b/tests/ui/impl-trait/in-trait/signature-mismatch.rs index 1d63a6f3ce2..c84a3b8f46b 100644 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.rs +++ b/tests/ui/impl-trait/in-trait/signature-mismatch.rs @@ -1,4 +1,6 @@ // edition:2021 +// revisions: success failure +//[success] check-pass #![feature(return_position_impl_trait_in_trait)] #![allow(incomplete_features)] @@ -11,16 +13,25 @@ impl Captures<'_> for T {} trait Captures2<'a, 'b> {} impl Captures2<'_, '_> for T {} -pub trait AsyncTrait { +trait AsyncTrait { + #[cfg(success)] fn async_fn(&self, buff: &[u8]) -> impl Future>; + + #[cfg(success)] fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future>; + + #[cfg(success)] fn async_fn_multiple<'a>(&'a self, buff: &[u8]) - -> impl Future> + Captures<'a>; + -> impl Future> + Captures<'a>; + + #[cfg(failure)] fn async_fn_reduce_outlive<'a, T>( &'a self, buff: &[u8], t: T, ) -> impl Future> + 'a; + + #[cfg(success)] fn async_fn_reduce<'a, T>( &'a self, buff: &[u8], @@ -31,38 +42,49 @@ pub trait AsyncTrait { pub struct Struct; impl AsyncTrait for Struct { + // Does not capture more lifetimes that trait def'n, since trait def'n + // implicitly captures all in-scope lifetimes. + #[cfg(success)] fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { - //~^ ERROR return type captures more lifetimes than trait definition async move { buff.to_vec() } } + // Does not capture more lifetimes that trait def'n, since trait def'n + // implicitly captures all in-scope lifetimes. + #[cfg(success)] fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { - //~^ ERROR return type captures more lifetimes than trait definition async move { buff.to_vec() } } + // Does not capture more lifetimes that trait def'n, since trait def'n + // implicitly captures all in-scope lifetimes. + #[cfg(success)] fn async_fn_multiple<'a, 'b>( &'a self, buff: &'b [u8], ) -> impl Future> + Captures2<'a, 'b> { - //~^ ERROR return type captures more lifetimes than trait definition async move { buff.to_vec() } } + // This error message is awkward, but `impl Future>` + // cannot outlive `'a` (from the trait signature) because it captures + // both `T` and `'b`. + #[cfg(failure)] fn async_fn_reduce_outlive<'a, 'b, T>( &'a self, buff: &'b [u8], t: T, ) -> impl Future> { - //~^ ERROR the parameter type `T` may not live long enough + //[failure]~^ ERROR lifetime mismatch async move { let _t = t; vec![] } } - // OK: We remove the `Captures<'a>`, providing a guarantee that we don't capture `'a`, - // but we still fulfill the `Captures<'a>` trait bound. + // Does not capture fewer lifetimes that trait def'n (not that it matters), + // since impl also captures all in-scope lifetimes. + #[cfg(success)] fn async_fn_reduce<'a, 'b, T>(&'a self, buff: &'b [u8], t: T) -> impl Future> { async move { let _t = t; diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr deleted file mode 100644 index 616f1ac35a9..00000000000 --- a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr +++ /dev/null @@ -1,61 +0,0 @@ -error: return type captures more lifetimes than trait definition - --> $DIR/signature-mismatch.rs:34:47 - | -LL | fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { - | -- this lifetime was captured ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/signature-mismatch.rs:15:40 - | -LL | fn async_fn(&self, buff: &[u8]) -> impl Future>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: hidden type inferred to be `impl Future> + 'a` - -error: return type captures more lifetimes than trait definition - --> $DIR/signature-mismatch.rs:39:57 - | -LL | fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future> + 'a { - | -- this lifetime was captured ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/signature-mismatch.rs:16:57 - | -LL | fn async_fn_early<'a: 'a>(&self, buff: &'a [u8]) -> impl Future>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: hidden type inferred to be `impl Future> + 'a` - -error: return type captures more lifetimes than trait definition - --> $DIR/signature-mismatch.rs:47:10 - | -LL | fn async_fn_multiple<'a, 'b>( - | -- this lifetime was captured -... -LL | ) -> impl Future> + Captures2<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/signature-mismatch.rs:18:12 - | -LL | -> impl Future> + Captures<'a>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: hidden type inferred to be `impl Future> + Captures2<'a, 'b>` - -error[E0309]: the parameter type `T` may not live long enough - --> $DIR/signature-mismatch.rs:56:10 - | -LL | ) -> impl Future> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `impl Future>` will meet its required lifetime bounds... - | -note: ...that is required by this bound - --> $DIR/signature-mismatch.rs:23:42 - | -LL | ) -> impl Future> + 'a; - | ^^ -help: consider adding an explicit lifetime bound... - | -LL | fn async_fn_reduce_outlive<'a, 'b, T: 'a>( - | ++++ - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0309`. diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs new file mode 100644 index 00000000000..f8e4ab88c19 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -0,0 +1,20 @@ +#![feature(rustc_attrs, return_position_impl_trait_in_trait)] +#![allow(internal_features)] +#![rustc_variance_of_opaques] + +trait Captures<'a> {} +impl Captures<'_> for T {} + +trait Foo<'i> { + fn implicit_capture_early<'a: 'a>() -> impl Sized {} + //~^ [o, *, *, o, o] + // Self, 'i, 'a, 'i_duplicated, 'a_duplicated + + fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [o, *, *, o, o] + + fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} //~ [o, *, o, o] + + fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o, *, o, o] +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr new file mode 100644 index 00000000000..8cae5a92f0d --- /dev/null +++ b/tests/ui/impl-trait/in-trait/variance.stderr @@ -0,0 +1,26 @@ +error: [o, *, *, o, o] + --> $DIR/variance.rs:9:44 + | +LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {} + | ^^^^^^^^^^ + +error: [o, *, *, o, o] + --> $DIR/variance.rs:13:44 + | +LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [o, *, o, o] + --> $DIR/variance.rs:15:48 + | +LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} + | ^^^^^^^^^^ + +error: [o, *, o, o] + --> $DIR/variance.rs:17:48 + | +LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/impl-trait/variance.rs b/tests/ui/impl-trait/variance.rs new file mode 100644 index 00000000000..d6212f8f393 --- /dev/null +++ b/tests/ui/impl-trait/variance.rs @@ -0,0 +1,16 @@ +#![feature(rustc_attrs)] +#![allow(internal_features)] +#![rustc_variance_of_opaques] + +trait Captures<'a> {} +impl Captures<'_> for T {} + +fn not_captured_early<'a: 'a>() -> impl Sized {} //~ [*] + +fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} //~ [*, o] + +fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} //~ [] + +fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} //~ [o] + +fn main() {} diff --git a/tests/ui/impl-trait/variance.stderr b/tests/ui/impl-trait/variance.stderr new file mode 100644 index 00000000000..64473675410 --- /dev/null +++ b/tests/ui/impl-trait/variance.stderr @@ -0,0 +1,26 @@ +error: [*] + --> $DIR/variance.rs:8:36 + | +LL | fn not_captured_early<'a: 'a>() -> impl Sized {} + | ^^^^^^^^^^ + +error: [*, o] + --> $DIR/variance.rs:10:32 + | +LL | fn captured_early<'a: 'a>() -> impl Sized + Captures<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [] + --> $DIR/variance.rs:12:40 + | +LL | fn not_captured_late<'a>(_: &'a ()) -> impl Sized {} + | ^^^^^^^^^^ + +error: [o] + --> $DIR/variance.rs:14:36 + | +LL | fn captured_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors +