Rollup merge of #131033 - compiler-errors:precise-capturing-in-traits, r=spastorino
Precise capturing in traits This PR begins to implement `feature(precise_capturing_in_traits)`, which enables using the `impl Trait + use<..>` syntax for RPITITs. It implements this by giving the desugared GATs variance, and representing the uncaptured lifetimes as bivariant, like how opaque captures work. Right now, I've left out implementing a necessary extension to the `refining_impl_trait` lint, and also I've made it so that all RPITITs always capture the parameters that come from the trait, because I'm not totally yet convinced that it's sound to not capture these args. It's certainly required to capture the type and const parameters from the trait (e.g. Self), or else users could bivariantly relate two RPITIT args that come from different impls, but region parameters don't affect trait selection in the same way, so it *may* be possible to relax this in the future. Let's stay conservative for now, though. I'm not totally sure what tests could be added on top of the ones I already added, since we really don't need to exercise the `precise_capturing` feature but simply what makes it special for RPITITs. r? types Tracking issue: * #130044
This commit is contained in:
commit
4f2af123eb
@ -1573,11 +1573,20 @@ fn lower_opaque_impl_trait(
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -565,6 +565,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
||||
(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.
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 visit_region(&mut self, r: ty::Region<'tcx>) {
|
||||
#[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 visit_ty(&mut self, t: Ty<'tcx>) {
|
||||
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 => {
|
||||
|
@ -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
|
||||
|
@ -539,6 +539,10 @@ fn trait_may_be_implemented_via_object(self, trait_def_id: DefId) -> bool {
|
||||
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())
|
||||
}
|
||||
|
@ -1479,6 +1479,7 @@
|
||||
powif64,
|
||||
pre_dash_lto: "pre-lto",
|
||||
precise_capturing,
|
||||
precise_capturing_in_traits,
|
||||
precise_pointer_size_matching,
|
||||
pref_align_of,
|
||||
prefetch_read_data,
|
||||
|
@ -261,6 +261,8 @@ fn for_each_relevant_impl(
|
||||
|
||||
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;
|
||||
|
@ -254,6 +254,16 @@ fn relate<R: TypeRelation<I>>(
|
||||
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)?
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
trait Foo {
|
||||
fn test() -> impl Sized + use<Self>;
|
||||
//~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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<Self>;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope
|
||||
= note: see issue #130044 <https://github.com/rust-lang/rust/issues/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
|
||||
|
@ -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<T> 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 + Captures<'a> {}
|
||||
//~^ [Self: o, 'i: *, '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 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 + Captures<'a> {}
|
||||
//~^ [Self: o, 'i: *, '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 not_cpatured_late<'a>(_: &'a ()) -> impl Sized + use<'i, Self> {}
|
||||
//~^ [Self: o, 'i: o, 'i: o]
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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 + Captures<'a> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | fn explicit_capture_early<'a: 'a>() -> impl Sized + use<'i, 'a, Self> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: [Self: o, 'i: *, 'a: o, 'i: o]
|
||||
error: [Self: o, 'i: o, 'a: *, 'i: o]
|
||||
--> $DIR/variance.rs:12:40
|
||||
|
|
||||
LL | fn not_captured_early<'a: 'a>() -> impl Sized + use<'i, Self> {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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: aborting due to 4 previous errors
|
||||
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 6 previous errors
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
#![feature(precise_capturing_in_traits)]
|
||||
|
||||
fn type_param<T>() -> 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() {}
|
||||
|
@ -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<T>() -> impl Sized + use<> {}
|
||||
| - ^^^^^^^^^^^^^^^^^^
|
||||
@ -17,7 +9,7 @@ LL | fn type_param<T>() -> 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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() {}
|
||||
|
36
tests/ui/impl-trait/precise-capturing/redundant.stderr
Normal file
36
tests/ui/impl-trait/precise-capturing/redundant.stderr
Normal file
@ -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
|
||||
|
@ -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<Self>;
|
||||
//~^ 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
|
||||
}
|
||||
|
||||
|
@ -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<Self>;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= 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<Self>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= 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
|
||||
|
||||
|
@ -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<Self>;
|
||||
}
|
||||
|
||||
impl Trait for () {
|
||||
fn hello(self_: Invariant<'_>) -> impl Sized + use<'_> {}
|
||||
//~^ ERROR return type captures more lifetimes than trait definition
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -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<Self>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
= note: hidden type inferred to be `impl Sized`
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
@ -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<Self>;
|
||||
}
|
||||
#![feature(precise_capturing_in_traits)]
|
||||
|
||||
fn test<'a, 'b, T: for<'r> Foo<'r>>() {
|
||||
PartialEq::eq(
|
||||
&<T as Foo<'a>>::hello(),
|
||||
&<T as Foo<'b>>::hello(),
|
||||
fn eq_types<T>(_: T, _: T) {}
|
||||
|
||||
trait TraitLt<'a: 'a> {
|
||||
fn hello() -> impl Sized + use<Self>;
|
||||
//~^ 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
|
||||
<T as TraitLt<'a>>::hello(),
|
||||
<T as TraitLt<'b>>::hello(),
|
||||
);
|
||||
}
|
||||
|
||||
trait MethodLt {
|
||||
fn hello<'a: 'a>() -> impl Sized + use<Self>;
|
||||
}
|
||||
fn method_lt<'a, 'b, T: MethodLt> () {
|
||||
eq_types(
|
||||
T::hello::<'a>(),
|
||||
T::hello::<'b>(),
|
||||
);
|
||||
// Good!
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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<Self>;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= 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<Self>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ 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<Self>;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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 | | &<T as Foo<'a>>::hello(),
|
||||
LL | | &<T as Foo<'b>>::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 | | <T as TraitLt<'a>>::hello(),
|
||||
LL | | <T as TraitLt<'b>>::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 | | &<T as Foo<'a>>::hello(),
|
||||
LL | | &<T as Foo<'b>>::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 | | <T as TraitLt<'a>>::hello(),
|
||||
LL | | <T as TraitLt<'b>>::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
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
//@ check-pass
|
||||
|
||||
#![feature(precise_capturing_in_traits)]
|
||||
|
||||
trait Foo {
|
||||
fn bar<'a>() -> impl Sized + use<Self>;
|
||||
//~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
@ -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<Self>;
|
||||
| ^^^^^^^^^
|
||||
|
|
||||
= note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
Loading…
Reference in New Issue
Block a user