Begin AST lowering for precise captures
This commit is contained in:
parent
a076eae0d2
commit
647b672f16
@ -1399,7 +1399,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
|
hir::TyKind::TraitObject(bounds, lifetime_bound, *kind)
|
||||||
}
|
}
|
||||||
TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
|
TyKind::ImplTrait(def_node_id, bounds, precise_capturing) => {
|
||||||
assert!(precise_capturing.is_none(), "precise captures not supported yet!");
|
|
||||||
let span = t.span;
|
let span = t.span;
|
||||||
match itctx {
|
match itctx {
|
||||||
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
|
ImplTraitContext::OpaqueTy { origin, fn_kind } => self.lower_opaque_impl_trait(
|
||||||
@ -1409,8 +1408,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
bounds,
|
bounds,
|
||||||
fn_kind,
|
fn_kind,
|
||||||
itctx,
|
itctx,
|
||||||
|
precise_capturing.as_deref(),
|
||||||
),
|
),
|
||||||
ImplTraitContext::Universal => {
|
ImplTraitContext::Universal => {
|
||||||
|
assert!(
|
||||||
|
precise_capturing.is_none(),
|
||||||
|
"TODO: precise captures not supported on universals!"
|
||||||
|
);
|
||||||
let span = t.span;
|
let span = t.span;
|
||||||
|
|
||||||
// HACK: pprust breaks strings with newlines when the type
|
// HACK: pprust breaks strings with newlines when the type
|
||||||
@ -1521,6 +1525,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
bounds: &GenericBounds,
|
bounds: &GenericBounds,
|
||||||
fn_kind: Option<FnDeclKind>,
|
fn_kind: Option<FnDeclKind>,
|
||||||
itctx: ImplTraitContext,
|
itctx: ImplTraitContext,
|
||||||
|
precise_capturing: Option<&ast::GenericArgs>,
|
||||||
) -> hir::TyKind<'hir> {
|
) -> hir::TyKind<'hir> {
|
||||||
// Make sure we know that some funky desugaring has been going on here.
|
// Make sure we know that some funky desugaring has been going on here.
|
||||||
// This is a first: there is code in other places like for loop
|
// This is a first: there is code in other places like for loop
|
||||||
@ -1529,40 +1534,56 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||||||
// frequently opened issues show.
|
// frequently opened issues show.
|
||||||
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
|
||||||
|
|
||||||
let captured_lifetimes_to_duplicate = match origin {
|
let captured_lifetimes_to_duplicate = if let Some(precise_capturing) = precise_capturing {
|
||||||
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
let ast::GenericArgs::AngleBracketed(precise_capturing) = precise_capturing else {
|
||||||
// type alias impl trait and associated type position impl trait were
|
panic!("we only parse angle-bracketed args")
|
||||||
// decided to capture all in-scope lifetimes, which we collect for
|
};
|
||||||
// all opaques during resolution.
|
// We'll actually validate these later on; all we need is the list of
|
||||||
self.resolver
|
// lifetimes to duplicate during this portion of lowering.
|
||||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
precise_capturing
|
||||||
.into_iter()
|
.args
|
||||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
.iter()
|
||||||
.collect()
|
.filter_map(|arg| match arg {
|
||||||
}
|
ast::AngleBracketedArg::Arg(ast::GenericArg::Lifetime(lt)) => Some(*lt),
|
||||||
hir::OpaqueTyOrigin::FnReturn(..) => {
|
_ => None,
|
||||||
if matches!(
|
})
|
||||||
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
|
.collect()
|
||||||
FnDeclKind::Impl | FnDeclKind::Trait
|
} else {
|
||||||
) || self.tcx.features().lifetime_capture_rules_2024
|
match origin {
|
||||||
|| span.at_least_rust_2024()
|
hir::OpaqueTyOrigin::TyAlias { .. } => {
|
||||||
{
|
// type alias impl trait and associated type position impl trait were
|
||||||
// return-position impl trait in trait was decided to capture all
|
// decided to capture all in-scope lifetimes, which we collect for
|
||||||
// in-scope lifetimes, which we collect for all opaques during resolution.
|
// all opaques during resolution.
|
||||||
self.resolver
|
self.resolver
|
||||||
.take_extra_lifetime_params(opaque_ty_node_id)
|
.take_extra_lifetime_params(opaque_ty_node_id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(ident, id, _)| Lifetime { id, ident })
|
.map(|(ident, id, _)| Lifetime { id, ident })
|
||||||
.collect()
|
.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::FnReturn(..) => {
|
||||||
hir::OpaqueTyOrigin::AsyncFn(..) => {
|
if matches!(
|
||||||
unreachable!("should be using `lower_async_fn_ret_ty`")
|
fn_kind.expect("expected RPITs to be lowered with a FnKind"),
|
||||||
|
FnDeclKind::Impl | FnDeclKind::Trait
|
||||||
|
) || self.tcx.features().lifetime_capture_rules_2024
|
||||||
|
|| span.at_least_rust_2024()
|
||||||
|
{
|
||||||
|
// 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`")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
debug!(?captured_lifetimes_to_duplicate);
|
debug!(?captured_lifetimes_to_duplicate);
|
||||||
|
18
tests/ui/impl-trait/precise-capturing/higher-ranked.rs
Normal file
18
tests/ui/impl-trait/precise-capturing/higher-ranked.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// Show how precise captures allow us to skip capturing a higher-ranked lifetime
|
||||||
|
|
||||||
|
#![feature(lifetime_capture_rules_2024, precise_capturing)]
|
||||||
|
//~^ WARN the feature `precise_capturing` is incomplete
|
||||||
|
|
||||||
|
trait Trait<'a> {
|
||||||
|
type Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Trait<'_> for () {
|
||||||
|
type Item = Vec<()>;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hello() -> impl for<'a> Trait<'a, Item = impl use<> IntoIterator> {}
|
||||||
|
|
||||||
|
fn main() {}
|
11
tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
Normal file
11
tests/ui/impl-trait/precise-capturing/higher-ranked.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/higher-ranked.rs:5:41
|
||||||
|
|
|
||||||
|
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
16
tests/ui/impl-trait/precise-capturing/outlives.rs
Normal file
16
tests/ui/impl-trait/precise-capturing/outlives.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
// Show that precise captures allow us to skip a lifetime param for outlives
|
||||||
|
|
||||||
|
#![feature(lifetime_capture_rules_2024, precise_capturing)]
|
||||||
|
//~^ WARN the feature `precise_capturing` is incomplete
|
||||||
|
|
||||||
|
fn hello<'a: 'a, 'b: 'b>() -> impl use<'a> Sized { }
|
||||||
|
|
||||||
|
fn outlives<'a, T: 'a>(_: T) {}
|
||||||
|
|
||||||
|
fn test<'a, 'b>() {
|
||||||
|
outlives::<'a, _>(hello::<'a, 'b>());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
11
tests/ui/impl-trait/precise-capturing/outlives.stderr
Normal file
11
tests/ui/impl-trait/precise-capturing/outlives.stderr
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||||
|
--> $DIR/outlives.rs:5:41
|
||||||
|
|
|
||||||
|
LL | #![feature(lifetime_capture_rules_2024, precise_capturing)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
|
||||||
|
= note: `#[warn(incomplete_features)]` on by default
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user