Fix capturing duplicated lifetimes via parent
This commit is contained in:
parent
d1a0fa5ed3
commit
5daf58ffc1
3 changed files with 96 additions and 7 deletions
|
@ -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 expected_captures = UnordSet::default();
|
||||||
|
let mut shadowed_captures = UnordSet::default();
|
||||||
let mut seen_params = UnordMap::default();
|
let mut seen_params = UnordMap::default();
|
||||||
let mut prev_non_lifetime_param = None;
|
let mut prev_non_lifetime_param = None;
|
||||||
for arg in precise_capturing_args {
|
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) {
|
match tcx.named_bound_var(hir_id) {
|
||||||
Some(ResolvedArg::EarlyBound(def_id)) => {
|
Some(ResolvedArg::EarlyBound(def_id)) => {
|
||||||
expected_captures.insert(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(
|
tcx.dcx().span_delayed_bug(
|
||||||
|
@ -555,23 +571,30 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe
|
||||||
);
|
);
|
||||||
continue;
|
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 {
|
match param.kind {
|
||||||
ty::GenericParamDefKind::Lifetime => {
|
ty::GenericParamDefKind::Lifetime => {
|
||||||
// Check if the lifetime param was captured but isn't named in the precise captures list.
|
// Check if the lifetime param was captured but isn't named in the precise captures list.
|
||||||
if variances[param.index as usize] == ty::Invariant {
|
if variances[param.index as usize] == ty::Invariant {
|
||||||
let param_span =
|
let param_span = if let DefKind::OpaqueTy =
|
||||||
if let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
|
tcx.def_kind(tcx.parent(param.def_id))
|
||||||
|
&& let ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
|
||||||
| ty::ReLateParam(ty::LateParamRegion {
|
| ty::ReLateParam(ty::LateParamRegion {
|
||||||
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
|
bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
|
||||||
..
|
..
|
||||||
}) = *tcx
|
}) = *tcx
|
||||||
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
|
.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())
|
||||||
{
|
{
|
||||||
Some(tcx.def_span(def_id))
|
Some(tcx.def_span(def_id))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
// FIXME(precise_capturing): Structured suggestion for this would be useful
|
||||||
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
|
tcx.dcx().emit_err(errors::LifetimeNotCaptured {
|
||||||
use_span: tcx.def_span(param.def_id),
|
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…
Add table
Add a link
Reference in a new issue