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:
Matthias Krüger 2024-10-10 22:00:48 +02:00 committed by GitHub
commit 4f2af123eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 310 additions and 165 deletions

View File

@ -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();
}
}
_ => {}

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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 {

View File

@ -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 => {

View File

@ -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

View File

@ -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())
}

View File

@ -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,

View File

@ -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;

View File

@ -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)?
}

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {}

View 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

View File

@ -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
}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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

View File

@ -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() {}

View File

@ -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