Skip to content

Commit 2d74d8f

Browse files
committed
Actually capture all in-scope lifetimes.
1 parent 8f6e0a6 commit 2d74d8f

File tree

7 files changed

+75
-93
lines changed

7 files changed

+75
-93
lines changed

compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs

+29-43
Original file line numberDiff line numberDiff line change
@@ -557,37 +557,29 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
557557
/// like async desugaring.
558558
#[instrument(level = "debug", skip(self))]
559559
fn visit_opaque_ty(&mut self, opaque: &'tcx rustc_hir::OpaqueTy<'tcx>) {
560-
let mut captures = FxIndexMap::default();
560+
let captures = RefCell::new(FxIndexMap::default());
561561

562562
let capture_all_in_scope_lifetimes =
563563
opaque_captures_all_in_scope_lifetimes(self.tcx, opaque);
564564
if capture_all_in_scope_lifetimes {
565-
let mut create_def_for_duplicated_param = |original_lifetime: LocalDefId, def| {
566-
captures.entry(def).or_insert_with(|| {
567-
let name = self.tcx.item_name(original_lifetime.to_def_id());
568-
let span = self.tcx.def_span(original_lifetime);
569-
let feed = self.tcx.create_def(opaque.def_id, name, DefKind::LifetimeParam);
570-
feed.def_span(span);
571-
feed.def_ident_span(Some(span));
572-
feed.def_id()
573-
});
565+
let lifetime_ident = |def_id: LocalDefId| {
566+
let name = self.tcx.item_name(def_id.to_def_id());
567+
let span = self.tcx.def_span(def_id);
568+
Ident::new(name, span)
574569
};
575570

576571
// We list scopes outwards, this causes us to see lifetime parameters in reverse
577572
// declaration order. In order to make it consistent with what `generics_of` might
578573
// give, we will reverse the IndexMap after early captures.
579574
let mut scope = self.scope;
575+
let mut opaque_capture_scopes = vec![(opaque.def_id, &captures)];
580576
loop {
581577
match *scope {
582578
Scope::Binder { ref bound_vars, s, .. } => {
583-
for (&original_lifetime, &(mut def)) in bound_vars.iter().rev() {
579+
for (&original_lifetime, &def) in bound_vars.iter().rev() {
584580
if let DefKind::LifetimeParam = self.tcx.def_kind(original_lifetime) {
585-
if let Err(guar) =
586-
self.check_lifetime_is_capturable(opaque.def_id, def, None)
587-
{
588-
def = ResolvedArg::Error(guar);
589-
}
590-
create_def_for_duplicated_param(original_lifetime, def);
581+
let ident = lifetime_ident(original_lifetime);
582+
self.remap_opaque_captures(&opaque_capture_scopes, def, ident);
591583
}
592584
}
593585
scope = s;
@@ -598,25 +590,19 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
598590
let parent_generics = self.tcx.generics_of(parent_item);
599591
for param in parent_generics.own_params.iter().rev() {
600592
if let ty::GenericParamDefKind::Lifetime = param.kind {
601-
create_def_for_duplicated_param(
602-
param.def_id.expect_local(),
603-
ResolvedArg::EarlyBound(param.def_id.expect_local()),
604-
);
593+
let def = ResolvedArg::EarlyBound(param.def_id.expect_local());
594+
let ident = lifetime_ident(param.def_id.expect_local());
595+
self.remap_opaque_captures(&opaque_capture_scopes, def, ident);
605596
}
606597
}
607598
opt_parent_item = parent_generics.parent.and_then(DefId::as_local);
608599
}
609600
break;
610601
}
611602

612-
Scope::Opaque { captures: outer_captures, .. } => {
613-
for (_, &duplicated_param) in outer_captures.borrow().iter().rev() {
614-
create_def_for_duplicated_param(
615-
duplicated_param,
616-
ResolvedArg::EarlyBound(duplicated_param),
617-
);
618-
}
619-
break;
603+
Scope::Opaque { captures, def_id, s } => {
604+
opaque_capture_scopes.push((def_id, captures));
605+
scope = s;
620606
}
621607

622608
Scope::Body { .. } => {
@@ -631,18 +617,17 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
631617
}
632618
}
633619
}
634-
captures.reverse();
620+
captures.borrow_mut().reverse();
635621
}
636622

637-
let captures = RefCell::new(captures);
638-
639623
let scope = Scope::Opaque { captures: &captures, def_id: opaque.def_id, s: self.scope };
640624
self.with(scope, |this| {
641625
let scope = Scope::TraitRefBoundary { s: this.scope };
642626
this.with(scope, |this| intravisit::walk_opaque_ty(this, opaque))
643627
});
644628

645629
let captures = captures.into_inner().into_iter().collect();
630+
debug!(?captures);
646631
self.map.opaque_captured_lifetimes.insert(opaque.def_id, captures);
647632
}
648633

@@ -1297,7 +1282,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
12971282
};
12981283

12991284
if let Some(mut def) = result {
1300-
def = self.remap_opaque_captures(opaque_capture_scopes, def, lifetime_ref.ident);
1285+
def = self.remap_opaque_captures(&opaque_capture_scopes, def, lifetime_ref.ident);
13011286

13021287
if let ResolvedArg::EarlyBound(..) = def {
13031288
// Do not free early-bound regions, only late-bound ones.
@@ -1396,7 +1381,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
13961381
&self,
13971382
opaque_def_id: LocalDefId,
13981383
lifetime: ResolvedArg,
1399-
span: Option<Span>,
1384+
capture_span: Span,
14001385
) -> Result<(), ErrorGuaranteed> {
14011386
let ResolvedArg::LateBound(_, _, lifetime_def_id) = lifetime else { return Ok(()) };
14021387
let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id);
@@ -1416,10 +1401,8 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
14161401
};
14171402

14181403
let decl_span = self.tcx.def_span(lifetime_def_id);
1419-
let (span, label) = if let Some(span) = span
1420-
&& span != decl_span
1421-
{
1422-
(span, None)
1404+
let (span, label) = if capture_span != decl_span {
1405+
(capture_span, None)
14231406
} else {
14241407
let opaque_span = self.tcx.def_span(opaque_def_id);
14251408
(opaque_span, Some(opaque_span))
@@ -1435,19 +1418,22 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
14351418
Err(guar)
14361419
}
14371420

1421+
#[instrument(level = "trace", skip(self, opaque_capture_scopes), ret)]
14381422
fn remap_opaque_captures(
14391423
&self,
1440-
opaque_capture_scopes: Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>,
1424+
opaque_capture_scopes: &Vec<(LocalDefId, &RefCell<FxIndexMap<ResolvedArg, LocalDefId>>)>,
14411425
mut lifetime: ResolvedArg,
14421426
ident: Ident,
14431427
) -> ResolvedArg {
1444-
for (opaque_def_id, captures) in opaque_capture_scopes.into_iter().rev() {
1428+
if let Some(&(opaque_def_id, _)) = opaque_capture_scopes.last() {
14451429
if let Err(guar) =
1446-
self.check_lifetime_is_capturable(opaque_def_id, lifetime, Some(ident.span))
1430+
self.check_lifetime_is_capturable(opaque_def_id, lifetime, ident.span)
14471431
{
1448-
return ResolvedArg::Error(guar);
1432+
lifetime = ResolvedArg::Error(guar);
14491433
}
1434+
}
14501435

1436+
for &(opaque_def_id, captures) in opaque_capture_scopes.iter().rev() {
14511437
let mut captures = captures.borrow_mut();
14521438
let remapped = *captures.entry(lifetime).or_insert_with(|| {
14531439
let feed = self.tcx.create_def(opaque_def_id, ident.name, DefKind::LifetimeParam);
@@ -1976,7 +1962,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
19761962
}
19771963
};
19781964

1979-
lifetime = self.remap_opaque_captures(opaque_capture_scopes, lifetime, lifetime_ref.ident);
1965+
lifetime = self.remap_opaque_captures(&opaque_capture_scopes, lifetime, lifetime_ref.ident);
19801966

19811967
self.insert_lifetime(lifetime_ref, lifetime);
19821968
}

tests/ui/associated-type-bounds/return-type-notation/impl-trait-in-trait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
trait IntFactory {
44
fn stream(self) -> impl IntFactory<stream(..): Send>;
5+
//~^ ERROR cycle detected when resolving lifetimes for `IntFactory::stream`
56
}
67

78
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0391]: cycle detected when resolving lifetimes for `IntFactory::stream`
2+
--> $DIR/impl-trait-in-trait.rs:4:5
3+
|
4+
LL | fn stream(self) -> impl IntFactory<stream(..): Send>;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
note: ...which requires computing function signature of `IntFactory::stream`...
8+
--> $DIR/impl-trait-in-trait.rs:4:5
9+
|
10+
LL | fn stream(self) -> impl IntFactory<stream(..): Send>;
11+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
12+
note: ...which requires looking up late bound vars inside `IntFactory::stream`...
13+
--> $DIR/impl-trait-in-trait.rs:4:5
14+
|
15+
LL | fn stream(self) -> impl IntFactory<stream(..): Send>;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
= note: ...which again requires resolving lifetimes for `IntFactory::stream`, completing the cycle
18+
note: cycle used when listing captured lifetimes for opaque `IntFactory::stream::{opaque#0}`
19+
--> $DIR/impl-trait-in-trait.rs:4:24
20+
|
21+
LL | fn stream(self) -> impl IntFactory<stream(..): Send>;
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
23+
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
24+
25+
error: aborting due to 1 previous error
26+
27+
For more information about this error, try `rustc --explain E0391`.

tests/ui/impl-trait/precise-capturing/capturing-implicit.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
#![rustc_variance_of_opaques]
77

88
fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
9-
//~^ ERROR []
10-
//~| ERROR []
9+
//~^ ERROR ['_: o]
10+
//~| ERROR ['_: o]
11+
//~| ERROR `impl Trait` captures lifetime parameter
1112
[*x]
1213
}
1314

Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1-
error: []
1+
error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list
2+
--> $DIR/capturing-implicit.rs:8:11
3+
|
4+
LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
5+
| ^ -------------------------------------------- lifetime captured due to being mentioned in the bounds of the `impl Trait`
6+
| |
7+
| this lifetime parameter is captured
8+
9+
error: ['_: o]
210
--> $DIR/capturing-implicit.rs:8:19
311
|
412
LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
513
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
614

7-
error: []
15+
error: ['_: o]
816
--> $DIR/capturing-implicit.rs:8:44
917
|
1018
LL | fn foo(x: &()) -> impl IntoIterator<Item = impl Sized> + use<> {
1119
| ^^^^^^^^^^
1220

13-
error: aborting due to 2 previous errors
21+
error: aborting due to 3 previous errors
1422

tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.rs

-3
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,14 @@ impl<T> Captures<'_> for T {}
55

66
fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
77
//~^ ERROR `impl Trait` cannot capture higher-ranked lifetime from `dyn` type
8-
//~| ERROR return type cannot have an unboxed trait object
98
loop {}
109
}
1110

1211
pub fn main() {
1312
//~^ ERROR item does not constrain `Opaque::{opaque#0}`, but has it in its signature
1413
type Opaque = impl Sized;
1514
fn define() -> Opaque {
16-
//~^ ERROR the size for values of type `(dyn Iterator<Item = impl Captures<'_>> + 'static)`
1715
let x: Opaque = dyn_hoops::<()>();
18-
//~^ ERROR the size for values of type `(dyn Iterator<Item = impl Captures<'_>> + 'static)`
1916
x
2017
}
2118
}

tests/ui/type-alias-impl-trait/bound-lifetime-through-dyn-trait.stderr

+4-42
Original file line numberDiff line numberDiff line change
@@ -10,57 +10,19 @@ note: lifetime declared here
1010
LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
1111
| ^^
1212

13-
error[E0746]: return type cannot have an unboxed trait object
14-
--> $DIR/bound-lifetime-through-dyn-trait.rs:6:29
15-
|
16-
LL | fn dyn_hoops<T: Sized>() -> dyn for<'a> Iterator<Item = impl Captures<'a>> {
17-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
18-
|
19-
help: consider returning an `impl Trait` instead of a `dyn Trait`
20-
|
21-
LL | fn dyn_hoops<T: Sized>() -> impl for<'a> Iterator<Item = impl Captures<'a>> {
22-
| ~~~~
23-
help: alternatively, box the return type, and wrap all of the returned values in `Box::new`
24-
|
25-
LL ~ fn dyn_hoops<T: Sized>() -> Box<dyn for<'a> Iterator<Item = impl Captures<'a>>> {
26-
LL |
27-
LL |
28-
LL ~ Box::new(loop {})
29-
|
30-
3113
error: item does not constrain `Opaque::{opaque#0}`, but has it in its signature
32-
--> $DIR/bound-lifetime-through-dyn-trait.rs:12:8
14+
--> $DIR/bound-lifetime-through-dyn-trait.rs:11:8
3315
|
3416
LL | pub fn main() {
3517
| ^^^^
3618
|
3719
= note: consider moving the opaque type's declaration and defining uses into a separate module
3820
note: this opaque type is in the signature
39-
--> $DIR/bound-lifetime-through-dyn-trait.rs:14:19
21+
--> $DIR/bound-lifetime-through-dyn-trait.rs:13:19
4022
|
4123
LL | type Opaque = impl Sized;
4224
| ^^^^^^^^^^
4325

44-
error[E0277]: the size for values of type `(dyn Iterator<Item = impl Captures<'_>> + 'static)` cannot be known at compilation time
45-
--> $DIR/bound-lifetime-through-dyn-trait.rs:15:20
46-
|
47-
LL | fn define() -> Opaque {
48-
| ^^^^^^ doesn't have a size known at compile-time
49-
...
50-
LL | x
51-
| - return type was inferred to be `(dyn Iterator<Item = impl Captures<'_>> + 'static)` here
52-
|
53-
= help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Captures<'_>> + 'static)`
54-
55-
error[E0277]: the size for values of type `(dyn Iterator<Item = impl Captures<'_>> + 'static)` cannot be known at compilation time
56-
--> $DIR/bound-lifetime-through-dyn-trait.rs:17:25
57-
|
58-
LL | let x: Opaque = dyn_hoops::<()>();
59-
| ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
60-
|
61-
= help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Captures<'_>> + 'static)`
62-
63-
error: aborting due to 5 previous errors
26+
error: aborting due to 2 previous errors
6427

65-
Some errors have detailed explanations: E0277, E0657, E0746.
66-
For more information about an error, try `rustc --explain E0277`.
28+
For more information about this error, try `rustc --explain E0657`.

0 commit comments

Comments
 (0)