Rollup merge of #124104 - compiler-errors:parent-generic-use, r=oli-obk
Fix capturing duplicated lifetimes via parent in `precise_captures` (`impl use<'...>`) For technical reasons related to the way that `Self` and `T::Assoc` are lowered from HIR -> `rustc_middle::ty`, an opaque may mention in its bounds both the original early-bound lifetime from the parent `impl`/`fn`, *and* the *duplicated* early-bound lifetime on the opaque. This is fine -- and has been fine since `@cjgillot` rewrote the way we handled opaque lifetime captures, and we went further to allow this behavior explicitly in https://github.com/rust-lang/rust/pull/115659. It's worthwhile to read this PR's technical section to recall how this duplication works and when it acts surprisingly. The problem here is that the check that make sure that `impl use<'a, 'b>` lists all of the opaque's captured lifetimes wasn't smart enough to consider both these captured lifetimes and the original lifetimes they're duplicated from to be equal. This PR fixes that. r? oli-obk
This commit is contained in:
commit
ff9a0b19ff
@ -492,6 +492,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
|
||||
};
|
||||
|
||||
let mut expected_captures = UnordSet::default();
|
||||
let mut shadowed_captures = UnordSet::default();
|
||||
let mut seen_params = UnordMap::default();
|
||||
let mut prev_non_lifetime_param = None;
|
||||
for arg in precise_capturing_args {
|
||||
@ -530,6 +531,21 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
|
||||
match tcx.named_bound_var(hir_id) {
|
||||
Some(ResolvedArg::EarlyBound(def_id)) => {
|
||||
expected_captures.insert(def_id);
|
||||
|
||||
// Make sure we allow capturing these lifetimes through `Self` and
|
||||
// `T::Assoc` projection syntax, too. These will occur when we only
|
||||
// see lifetimes are captured after hir-lowering -- this aligns with
|
||||
// the cases that were stabilized with the `impl_trait_projection`
|
||||
// feature -- see <https://github.com/rust-lang/rust/pull/115659>.
|
||||
if let DefKind::LifetimeParam = tcx.def_kind(def_id)
|
||||
&& let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
|
||||
| ty::ReLateParam(ty::LateParamRegion {
|
||||
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
|
||||
..
|
||||
}) = *tcx.map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
|
||||
{
|
||||
shadowed_captures.insert(def_id);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
tcx.dcx().span_delayed_bug(
|
||||
@ -555,23 +571,30 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
|
||||
);
|
||||
continue;
|
||||
}
|
||||
// If a param is shadowed by a early-bound (duplicated) lifetime, then
|
||||
// it may or may not be captured as invariant, depending on if it shows
|
||||
// up through `Self` or `T::Assoc` syntax.
|
||||
if shadowed_captures.contains(¶m.def_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
match param.kind {
|
||||
ty::GenericParamDefKind::Lifetime => {
|
||||
// Check if the lifetime param was captured but isn't named in the precise captures list.
|
||||
if variances[param.index as usize] == ty::Invariant {
|
||||
let param_span =
|
||||
if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
|
||||
let param_span = if let DefKind::OpaqueTy =
|
||||
tcx.def_kind(tcx.parent(param.def_id))
|
||||
&& let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
|
||||
| ty::ReLateParam(ty::LateParamRegion {
|
||||
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
|
||||
..
|
||||
}) = *tcx
|
||||
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
|
||||
{
|
||||
Some(tcx.def_span(def_id))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
{
|
||||
Some(tcx.def_span(def_id))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
||||
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
|
||||
use_span: tcx.def_span(param.def_id),
|
||||
|
38
tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
Normal file
38
tests/ui/impl-trait/precise-capturing/capture-parent-arg.rs
Normal file
@ -0,0 +1,38 @@
|
||||
#![feature(precise_capturing)]
|
||||
//~^ WARN the feature `precise_capturing` is incomplete
|
||||
|
||||
trait Tr {
|
||||
type Assoc;
|
||||
}
|
||||
|
||||
struct W<'a>(&'a ());
|
||||
|
||||
impl Tr for W<'_> {
|
||||
type Assoc = ();
|
||||
}
|
||||
|
||||
// The normal way of capturing `'a`...
|
||||
impl<'a> W<'a> {
|
||||
fn good1() -> impl use<'a> Into<<W<'a> as Tr>::Assoc> {}
|
||||
}
|
||||
|
||||
// This ensures that we don't error when we capture the *parent* copy of `'a`,
|
||||
// since the opaque captures that rather than the duplicated `'a` lifetime
|
||||
// synthesized from mentioning `'a` directly in the bounds.
|
||||
impl<'a> W<'a> {
|
||||
fn good2() -> impl use<'a> Into<<Self as Tr>::Assoc> {}
|
||||
}
|
||||
|
||||
// The normal way of capturing `'a`... but not mentioned in the bounds.
|
||||
impl<'a> W<'a> {
|
||||
fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
|
||||
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
|
||||
}
|
||||
|
||||
// But also make sure that we error here...
|
||||
impl<'a> W<'a> {
|
||||
//~^ ERROR `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
|
||||
fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,28 @@
|
||||
warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/capture-parent-arg.rs:1:12
|
||||
|
|
||||
LL | #![feature(precise_capturing)]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
|
||||
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
|
||||
--> $DIR/capture-parent-arg.rs:28:37
|
||||
|
|
||||
LL | impl<'a> W<'a> {
|
||||
| -- this lifetime parameter is captured
|
||||
LL | fn bad1() -> impl use<> Into<<W<'a> as Tr>::Assoc> {}
|
||||
| -------------------^^---------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
|
||||
|
||||
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
|
||||
--> $DIR/capture-parent-arg.rs:33:6
|
||||
|
|
||||
LL | impl<'a> W<'a> {
|
||||
| ^^
|
||||
LL |
|
||||
LL | fn bad2() -> impl use<> Into<<Self as Tr>::Assoc> {}
|
||||
| ------------------------------------ lifetime captured due to being mentioned in the bounds of the `impl Trait`
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
Loading…
x
Reference in New Issue
Block a user