diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b26797f42032f..35af4d63cc760 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1573,11 +1573,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Feature gate for RPITIT + use<..> match origin { rustc_hir::OpaqueTyOrigin::FnReturn { in_trait_or_impl: Some(_), .. } => { - if let Some(span) = bounds.iter().find_map(|bound| match *bound { - ast::GenericBound::Use(_, span) => Some(span), - _ => None, - }) { - self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span }); + if !self.tcx.features().precise_capturing_in_traits + && let Some(span) = bounds.iter().find_map(|bound| match *bound { + ast::GenericBound::Use(_, span) => Some(span), + _ => None, + }) + { + let mut diag = + self.tcx.dcx().create_err(errors::NoPreciseCapturesOnRpitit { span }); + add_feature_diagnostics( + &mut diag, + self.tcx.sess, + sym::precise_capturing_in_traits, + ); + diag.emit(); } } _ => {} diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 380e36fe40566..19a6960cf4d88 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -565,6 +565,8 @@ declare_features! ( (incomplete, pin_ergonomics, "CURRENT_RUSTC_VERSION", Some(130494)), /// Allows postfix match `expr.match { ... }` (unstable, postfix_match, "1.79.0", Some(121618)), + /// Allows `use<..>` precise capturign on impl Trait in traits. + (unstable, precise_capturing_in_traits, "CURRENT_RUSTC_VERSION", Some(130044)), /// Allows macro attributes on expressions, statements and non-inline modules. (unstable, proc_macro_hygiene, "1.30.0", Some(54727)), /// Makes `&` and `&mut` patterns eat only one layer of references in Rust 2024. diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index c73826c489f96..a80dc87c62242 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -259,6 +259,9 @@ hir_analysis_late_bound_lifetime_in_apit = `impl Trait` can only mention lifetim hir_analysis_late_bound_type_in_apit = `impl Trait` can only mention type parameters from an fn or impl .label = type parameter declared here +hir_analysis_lifetime_implicitly_captured = `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list + .param_label = all lifetime parameters originating from a trait are captured implicitly + hir_analysis_lifetime_must_be_first = lifetime parameter `{$name}` must be listed before non-lifetime parameters .label = move the lifetime before this parameter diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index eb62ff86c7179..d0063b449f894 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -589,15 +589,22 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe param_span: tcx.def_span(def_id), }); } else { - // If the `use_span` is actually just the param itself, then we must - // have not duplicated the lifetime but captured the original. - // The "effective" `use_span` will be the span of the opaque itself, - // and the param span will be the def span of the param. - tcx.dcx().emit_err(errors::LifetimeNotCaptured { - opaque_span, - use_span: opaque_span, - param_span: use_span, - }); + if tcx.def_kind(tcx.parent(param.def_id)) == DefKind::Trait { + tcx.dcx().emit_err(errors::LifetimeImplicitlyCaptured { + opaque_span, + param_span: tcx.def_span(param.def_id), + }); + } else { + // If the `use_span` is actually just the param itself, then we must + // have not duplicated the lifetime but captured the original. + // The "effective" `use_span` will be the span of the opaque itself, + // and the param span will be the def span of the param. + tcx.dcx().emit_err(errors::LifetimeNotCaptured { + opaque_span, + use_span: opaque_span, + param_span: use_span, + }); + } } continue; } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 80334c6efe7d6..2d6b9813271e2 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -64,6 +64,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; }; + if hidden_tys.items().any(|(_, &ty)| ty.skip_binder().references_error()) { + return; + } + let mut collector = ImplTraitInTraitCollector { tcx, types: FxIndexSet::default() }; trait_m_sig.visit_with(&mut collector); diff --git a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs index b6cffb90805b3..8a83866b7fa46 100644 --- a/compiler/rustc_hir_analysis/src/errors/precise_captures.rs +++ b/compiler/rustc_hir_analysis/src/errors/precise_captures.rs @@ -34,6 +34,15 @@ pub(crate) struct LifetimeNotCaptured { pub opaque_span: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_lifetime_implicitly_captured)] +pub(crate) struct LifetimeImplicitlyCaptured { + #[primary_span] + pub opaque_span: Span, + #[label(hir_analysis_param_label)] + pub param_span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_bad_precise_capture)] pub(crate) struct BadPreciseCapture { diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index 12bb9a3f9e0f3..02cfb57b836f6 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -5,6 +5,7 @@ use itertools::Itertools; use rustc_arena::DroplessArena; +use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::query::Providers; @@ -63,8 +64,29 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { let crate_map = tcx.crate_variances(()); return crate_map.variances.get(&item_def_id.to_def_id()).copied().unwrap_or(&[]); } + DefKind::AssocTy => match tcx.opt_rpitit_info(item_def_id.to_def_id()) { + Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => { + return variance_of_opaque( + tcx, + opaque_def_id.expect_local(), + ForceCaptureTraitArgs::Yes, + ); + } + None | Some(ty::ImplTraitInTraitData::Impl { .. }) => {} + }, DefKind::OpaqueTy => { - return variance_of_opaque(tcx, item_def_id); + let force_capture_trait_args = if let hir::OpaqueTyOrigin::FnReturn { + parent: _, + in_trait_or_impl: Some(hir::RpitContext::Trait), + } = + tcx.hir_node_by_def_id(item_def_id).expect_opaque_ty().origin + { + ForceCaptureTraitArgs::Yes + } else { + ForceCaptureTraitArgs::No + }; + + return variance_of_opaque(tcx, item_def_id, force_capture_trait_args); } _ => {} } @@ -73,8 +95,18 @@ fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { span_bug!(tcx.def_span(item_def_id), "asked to compute variance for wrong kind of item"); } +#[derive(Debug, Copy, Clone)] +enum ForceCaptureTraitArgs { + Yes, + No, +} + #[instrument(level = "trace", skip(tcx), ret)] -fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] { +fn variance_of_opaque( + tcx: TyCtxt<'_>, + item_def_id: LocalDefId, + force_capture_trait_args: ForceCaptureTraitArgs, +) -> &[ty::Variance] { let generics = tcx.generics_of(item_def_id); // Opaque types may only use regions that are bound. So for @@ -115,9 +147,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc #[instrument(level = "trace", skip(self), ret)] fn visit_ty(&mut self, t: Ty<'tcx>) { match t.kind() { - ty::Alias(_, ty::AliasTy { def_id, args, .. }) - if matches!(self.tcx.def_kind(*def_id), DefKind::OpaqueTy) => - { + ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { self.visit_opaque(*def_id, args); } _ => t.super_visit_with(self), @@ -135,6 +165,15 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc let mut generics = generics; while let Some(def_id) = generics.parent { generics = tcx.generics_of(def_id); + + // Don't mark trait params generic if we're in an RPITIT. + if matches!(force_capture_trait_args, ForceCaptureTraitArgs::Yes) + && generics.parent.is_none() + { + debug_assert_eq!(tcx.def_kind(def_id), DefKind::Trait); + break; + } + for param in &generics.own_params { match param.kind { ty::GenericParamDefKind::Lifetime => { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 610c682d3a461..afe03531861c9 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1100,9 +1100,12 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def | DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn => true, + DefKind::AssocTy => { + // Only encode variances for RPITITs (for traits) + matches!(tcx.opt_rpitit_info(def_id), Some(ty::ImplTraitInTraitData::Trait { .. })) + } DefKind::Mod | DefKind::Field - | DefKind::AssocTy | DefKind::AssocConst | DefKind::TyParam | DefKind::ConstParam diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 90265f67bc1f6..590e1d336f340 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -539,6 +539,10 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.trait_def(trait_def_id).implement_via_object } + fn is_impl_trait_in_trait(self, def_id: DefId) -> bool { + self.is_impl_trait_in_trait(def_id) + } + fn delay_bug(self, msg: impl ToString) -> ErrorGuaranteed { self.dcx().span_delayed_bug(DUMMY_SP, msg.to_string()) } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 1527600e764c0..683f59a89995e 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1479,6 +1479,7 @@ symbols! { powif64, pre_dash_lto: "pre-lto", precise_capturing, + precise_capturing_in_traits, precise_pointer_size_matching, pref_align_of, prefetch_read_data, diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a72e7b482a6fd..f06017d7e5c35 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -261,6 +261,8 @@ pub trait Interner: fn trait_may_be_implemented_via_object(self, trait_def_id: Self::DefId) -> bool; + fn is_impl_trait_in_trait(self, def_id: Self::DefId) -> bool; + fn delay_bug(self, msg: impl ToString) -> Self::ErrorGuaranteed; fn is_general_coroutine(self, coroutine_def_id: Self::DefId) -> bool; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 1302906adab1f..e1f3e493e36e3 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -254,6 +254,16 @@ impl Relate for ty::AliasTy { b.args, false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, + ty::Projection if relation.cx().is_impl_trait_in_trait(a.def_id) => { + relate_args_with_variances( + relation, + a.def_id, + relation.cx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )? + } ty::Projection | ty::Weak | ty::Inherent => { relate_args_invariantly(relation, a.args, b.args)? } diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs new file mode 100644 index 0000000000000..308b41dfc68ab --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.rs @@ -0,0 +1,6 @@ +trait Foo { + fn test() -> impl Sized + use; + //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position +} + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr new file mode 100644 index 0000000000000..b2c6bf61124d9 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-precise_capturing_in_traits.stderr @@ -0,0 +1,13 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/feature-gate-precise_capturing_in_traits.rs:2:31 + | +LL | fn test() -> impl Sized + use; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + = note: see issue #130044 for more information + = help: add `#![feature(precise_capturing_in_traits)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/in-trait/variance.rs b/tests/ui/impl-trait/in-trait/variance.rs index 0ac44bf7546c2..19905c608e3b5 100644 --- a/tests/ui/impl-trait/in-trait/variance.rs +++ b/tests/ui/impl-trait/in-trait/variance.rs @@ -1,22 +1,25 @@ -#![feature(rustc_attrs)] +#![feature(rustc_attrs, precise_capturing_in_traits)] #![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 {} - //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] + + fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} + //~^ [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] - fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} - //~^ [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] + fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} + //~^ [Self: o, 'i: o, 'a: *, 'i: o] fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} - //~^ [Self: o, 'i: *, 'a: o, 'i: o] + //~^ [Self: o, 'i: o, 'a: o, 'i: o] + + fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} + //~^ [Self: o, 'i: o, 'i: o, 'a: o] - fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} - //~^ [Self: o, 'i: *, 'a: o, 'i: o] + fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} + //~^ [Self: o, 'i: o, 'i: o] } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/variance.stderr b/tests/ui/impl-trait/in-trait/variance.stderr index 54e0afbaa950d..f65174e1c358c 100644 --- a/tests/ui/impl-trait/in-trait/variance.stderr +++ b/tests/ui/impl-trait/in-trait/variance.stderr @@ -1,26 +1,38 @@ -error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] - --> $DIR/variance.rs:9:44 +error: [Self: o, 'i: o, 'a: *, 'a: o, 'i: o] + --> $DIR/variance.rs:6:44 | LL | fn implicit_capture_early<'a: 'a>() -> impl Sized {} | ^^^^^^^^^^ -error: [Self: o, 'i: *, 'a: *, 'a: o, 'i: o] - --> $DIR/variance.rs:12:44 +error: [Self: o, 'i: o, 'a: *, 'i: o, 'a: o] + --> $DIR/variance.rs:9:44 + | +LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [Self: o, 'i: o, 'a: *, 'i: o] + --> $DIR/variance.rs:12:40 | -LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + Captures<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: [Self: o, 'i: *, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'a: o, 'i: o] --> $DIR/variance.rs:15:48 | LL | fn implicit_capture_late<'a>(_: &'a ()) -> impl Sized {} | ^^^^^^^^^^ -error: [Self: o, 'i: *, 'a: o, 'i: o] +error: [Self: o, 'i: o, 'i: o, 'a: o] --> $DIR/variance.rs:18:48 | -LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + Captures<'a> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn explicit_capture_late<'a>(_: &'a ()) -> impl Sized + use<'i, 'a, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: [Self: o, 'i: o, 'i: o] + --> $DIR/variance.rs:21:44 + | +LL | fn not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 9d68819f657db..6c2477c9744ab 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -1,10 +1,11 @@ +#![feature(precise_capturing_in_traits)] + fn type_param() -> impl Sized + use<> {} //~^ ERROR `impl Trait` must mention all type parameters in scope trait Foo { fn bar() -> impl Sized + use<>; //~^ ERROR `impl Trait` must mention the `Self` type of the trait - //~| ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index d9be9d543e450..93b44a0c18c27 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,13 +1,5 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/forgot-to-capture-type.rs:5:30 - | -LL | fn bar() -> impl Sized + use<>; - | ^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - error: `impl Trait` must mention all type parameters in scope in `use<...>` - --> $DIR/forgot-to-capture-type.rs:1:23 + --> $DIR/forgot-to-capture-type.rs:3:23 | LL | fn type_param() -> impl Sized + use<> {} | - ^^^^^^^^^^^^^^^^^^ @@ -17,7 +9,7 @@ LL | fn type_param() -> impl Sized + use<> {} = note: currently, all type parameters are required to be mentioned in the precise captures list error: `impl Trait` must mention the `Self` type of the trait in `use<...>` - --> $DIR/forgot-to-capture-type.rs:5:17 + --> $DIR/forgot-to-capture-type.rs:7:17 | LL | trait Foo { | --------- `Self` type parameter is implicitly captured by this `impl Trait` @@ -26,5 +18,5 @@ LL | fn bar() -> impl Sized + use<>; | = note: currently, all type parameters are required to be mentioned in the precise captures list -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr deleted file mode 100644 index d1bcbaa33ae2b..0000000000000 --- a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:5:19 - | -LL | fn hello<'a>() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - | - = note: `#[warn(impl_trait_redundant_captures)]` on by default - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:10:27 - | -LL | fn inherent(&self) -> impl Sized + use<'_> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - -warning: 2 warnings emitted - diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr deleted file mode 100644 index 213888356e572..0000000000000 --- a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/redundant.rs:16:35 - | -LL | fn in_trait() -> impl Sized + use<'a, Self>; - | ^^^^^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/redundant.rs:21:35 - | -LL | fn in_trait() -> impl Sized + use<'a> {} - | ^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - -error: aborting due to 2 previous errors - diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 4a08ffb61be03..e19d935f5b0d4 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -1,25 +1,24 @@ //@ compile-flags: -Zunstable-options --edition=2024 -//@ revisions: normal rpitit -//@[normal] check-pass +//@ check-pass + +#![feature(precise_capturing_in_traits)] fn hello<'a>() -> impl Sized + use<'a> {} -//[normal]~^ WARN all possible in-scope parameters are already captured +//~^ WARN all possible in-scope parameters are already captured struct Inherent; impl Inherent { fn inherent(&self) -> impl Sized + use<'_> {} - //[normal]~^ WARN all possible in-scope parameters are already captured + //~^ WARN all possible in-scope parameters are already captured } -#[cfg(rpitit)] trait Test<'a> { fn in_trait() -> impl Sized + use<'a, Self>; - //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + //~^ WARN all possible in-scope parameters are already captured } -#[cfg(rpitit)] impl<'a> Test<'a> for () { fn in_trait() -> impl Sized + use<'a> {} - //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + //~^ WARN all possible in-scope parameters are already captured } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr new file mode 100644 index 0000000000000..274d9d2375f7d --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr @@ -0,0 +1,36 @@ +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:6:19 + | +LL | fn hello<'a>() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + | + = note: `#[warn(impl_trait_redundant_captures)]` on by default + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:11:27 + | +LL | fn inherent(&self) -> impl Sized + use<'_> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:16:22 + | +LL | fn in_trait() -> impl Sized + use<'a, Self>; + | ^^^^^^^^^^^^^------------- + | | + | help: remove the `use<...>` syntax + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:20:22 + | +LL | fn in_trait() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + +warning: 4 warnings emitted + diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs index 062351afecbdf..b39c1408c0509 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.rs @@ -2,13 +2,14 @@ // trait definition, which is not allowed. Due to the default lifetime capture // rules of RPITITs, this is only doable if we use precise capturing. +#![feature(precise_capturing_in_traits)] + pub trait Foo { fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; - //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } impl Foo for () { - fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} + fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} //~^ ERROR return type captures more lifetimes than trait definition } diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr index b390a23eef414..45f755d3cc1be 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit-captures-more-method-lifetimes.stderr @@ -1,25 +1,17 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:53 - | -LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - error: return type captures more lifetimes than trait definition - --> $DIR/rpitit-captures-more-method-lifetimes.rs:11:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:12:40 | -LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + 'im {} - | --- ^^^^^^^^^^^^^^^^ +LL | fn bar<'im: 'im>(&'im mut self) -> impl Sized + use<'im> {} + | --- ^^^^^^^^^^^^^^^^^^^^^ | | | this lifetime was captured | note: hidden type must only reference lifetimes captured by this impl trait - --> $DIR/rpitit-captures-more-method-lifetimes.rs:6:40 + --> $DIR/rpitit-captures-more-method-lifetimes.rs:8:40 | LL | fn bar<'tr: 'tr>(&'tr mut self) -> impl Sized + use; | ^^^^^^^^^^^^^^^^^^^^^^ - = note: hidden type inferred to be `impl Sized + 'im` + = note: hidden type inferred to be `impl Sized` -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs new file mode 100644 index 0000000000000..b16b0522d6e11 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.rs @@ -0,0 +1,14 @@ +#![feature(precise_capturing_in_traits)] + +struct Invariant<'a>(&'a mut &'a mut ()); + +trait Trait { + fn hello(self_: Invariant<'_>) -> impl Sized + use; +} + +impl Trait for () { + fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {} + //~^ ERROR return type captures more lifetimes than trait definition +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr new file mode 100644 index 0000000000000..e1856b929106e --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit-impl-captures-too-much.stderr @@ -0,0 +1,17 @@ +error: return type captures more lifetimes than trait definition + --> $DIR/rpitit-impl-captures-too-much.rs:10:39 + | +LL | fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {} + | -- ^^^^^^^^^^^^^^^^^^^^ + | | + | this lifetime was captured + | +note: hidden type must only reference lifetimes captured by this impl trait + --> $DIR/rpitit-impl-captures-too-much.rs:6:39 + | +LL | fn hello(self_: Invariant<'_>) -> impl Sized + use; + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: hidden type inferred to be `impl Sized` + +error: aborting due to 1 previous error + diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs index feeeb1461e827..3f887e8e47f1c 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.rs +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -1,19 +1,34 @@ -//@ known-bug: unknown - // RPITITs don't have variances in their GATs, so they always relate invariantly // and act as if they capture all their args. // To fix this soundly, we need to make sure that all the trait header args // remain captured, since they affect trait selection. -trait Foo<'a> { - fn hello() -> impl PartialEq + use; +#![feature(precise_capturing_in_traits)] + +fn eq_types(_: T, _: T) {} + +trait TraitLt<'a: 'a> { + fn hello() -> impl Sized + use; + //~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list +} +fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { + eq_types( + //~^ ERROR lifetime may not live long enough + //~| ERROR lifetime may not live long enough + >::hello(), + >::hello(), + ); } -fn test<'a, 'b, T: for<'r> Foo<'r>>() { - PartialEq::eq( - &>::hello(), - &>::hello(), +trait MethodLt { + fn hello<'a: 'a>() -> impl Sized + use; +} +fn method_lt<'a, 'b, T: MethodLt> () { + eq_types( + T::hello::<'a>(), + T::hello::<'b>(), ); + // Good! } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr index 5a120df9f047a..498eae54a1c68 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -1,44 +1,40 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/rpitit.rs:9:36 - | -LL | fn hello() -> impl PartialEq + use; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list - --> $DIR/rpitit.rs:9:19 + --> $DIR/rpitit.rs:11:19 | -LL | trait Foo<'a> { - | -- this lifetime parameter is captured -LL | fn hello() -> impl PartialEq + use; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` +LL | trait TraitLt<'a: 'a> { + | -- all lifetime parameters originating from a trait are captured implicitly +LL | fn hello() -> impl Sized + use; + | ^^^^^^^^^^^^^^^^^^^^^^ error: lifetime may not live long enough - --> $DIR/rpitit.rs:13:5 + --> $DIR/rpitit.rs:15:5 | -LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | / PartialEq::eq( -LL | | &>::hello(), -LL | | &>::hello(), +LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / eq_types( +LL | | +LL | | +LL | | >::hello(), +LL | | >::hello(), LL | | ); | |_____^ argument requires that `'a` must outlive `'b` | = help: consider adding the following bound: `'a: 'b` error: lifetime may not live long enough - --> $DIR/rpitit.rs:13:5 + --> $DIR/rpitit.rs:15:5 | -LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | / PartialEq::eq( -LL | | &>::hello(), -LL | | &>::hello(), +LL | fn trait_lt<'a, 'b, T: for<'r> TraitLt<'r>> () { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / eq_types( +LL | | +LL | | +LL | | >::hello(), +LL | | >::hello(), LL | | ); | |_____^ argument requires that `'b` must outlive `'a` | @@ -46,5 +42,5 @@ LL | | ); help: `'a` and `'b` must be the same: replace one with the other -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index a61a7f06edc1d..15985da50b55e 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,6 +1,9 @@ +//@ check-pass + +#![feature(precise_capturing_in_traits)] + trait Foo { fn bar<'a>() -> impl Sized + use; - //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr deleted file mode 100644 index c1974600f30c5..0000000000000 --- a/tests/ui/impl-trait/precise-capturing/self-capture.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits - --> $DIR/self-capture.rs:2:34 - | -LL | fn bar<'a>() -> impl Sized + use; - | ^^^^^^^^^ - | - = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope - -error: aborting due to 1 previous error -