Skip to content

Commit f8b287d

Browse files
Rollup merge of rust-lang#106578 - compiler-errors:recursive-opaque-closure, r=TaKO8Ki
Label closure captures/generator locals that make opaque types recursive cc rust-lang#46415 (comment)
2 parents 03a069c + 8742fd9 commit f8b287d

File tree

4 files changed

+99
-6
lines changed

4 files changed

+99
-6
lines changed

compiler/rustc_hir_analysis/src/check/check.rs

+53-6
Original file line numberDiff line numberDiff line change
@@ -1391,11 +1391,15 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed
13911391
///
13921392
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
13931393
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
1394-
fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
1394+
fn opaque_type_cycle_error(
1395+
tcx: TyCtxt<'_>,
1396+
opaque_def_id: LocalDefId,
1397+
span: Span,
1398+
) -> ErrorGuaranteed {
13951399
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
13961400

13971401
let mut label = false;
1398-
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
1402+
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
13991403
let typeck_results = tcx.typeck(def_id);
14001404
if visitor
14011405
.returns
@@ -1431,28 +1435,71 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
14311435
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
14321436
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
14331437
{
1434-
struct OpaqueTypeCollector(Vec<DefId>);
1438+
#[derive(Default)]
1439+
struct OpaqueTypeCollector {
1440+
opaques: Vec<DefId>,
1441+
closures: Vec<DefId>,
1442+
}
14351443
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
14361444
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
14371445
match *t.kind() {
14381446
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
1439-
self.0.push(def);
1447+
self.opaques.push(def);
14401448
ControlFlow::Continue(())
14411449
}
1450+
ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
1451+
self.closures.push(def_id);
1452+
t.super_visit_with(self)
1453+
}
14421454
_ => t.super_visit_with(self),
14431455
}
14441456
}
14451457
}
1446-
let mut visitor = OpaqueTypeCollector(vec![]);
1458+
1459+
let mut visitor = OpaqueTypeCollector::default();
14471460
ty.visit_with(&mut visitor);
1448-
for def_id in visitor.0 {
1461+
for def_id in visitor.opaques {
14491462
let ty_span = tcx.def_span(def_id);
14501463
if !seen.contains(&ty_span) {
14511464
err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
14521465
seen.insert(ty_span);
14531466
}
14541467
err.span_label(sp, &format!("returning here with type `{ty}`"));
14551468
}
1469+
1470+
for closure_def_id in visitor.closures {
1471+
let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
1472+
let typeck_results = tcx.typeck(closure_local_did);
1473+
1474+
let mut label_match = |ty: Ty<'_>, span| {
1475+
for arg in ty.walk() {
1476+
if let ty::GenericArgKind::Type(ty) = arg.unpack()
1477+
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
1478+
&& captured_def_id == opaque_def_id.to_def_id()
1479+
{
1480+
err.span_label(
1481+
span,
1482+
format!(
1483+
"{} captures itself here",
1484+
tcx.def_kind(closure_def_id).descr(closure_def_id)
1485+
),
1486+
);
1487+
}
1488+
}
1489+
};
1490+
1491+
// Label any closure upvars that capture the opaque
1492+
for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
1493+
{
1494+
label_match(capture.place.ty(), capture.get_path_span(tcx));
1495+
}
1496+
// Label any generator locals that capture the opaque
1497+
for interior_ty in
1498+
typeck_results.generator_interior_types.as_ref().skip_binder()
1499+
{
1500+
label_match(interior_ty.ty, interior_ty.span);
1501+
}
1502+
}
14561503
}
14571504
}
14581505
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#![feature(generators, generator_trait)]
2+
3+
use std::ops::{Generator, GeneratorState};
4+
5+
fn foo() -> impl Generator<Yield = (), Return = ()> {
6+
//~^ ERROR cannot resolve opaque type
7+
//~| NOTE recursive opaque type
8+
//~| NOTE in this expansion of desugaring of
9+
|| {
10+
//~^ NOTE returning here
11+
let mut gen = Box::pin(foo());
12+
//~^ NOTE generator captures itself here
13+
let mut r = gen.as_mut().resume(());
14+
while let GeneratorState::Yielded(v) = r {
15+
yield v;
16+
r = gen.as_mut().resume(());
17+
}
18+
}
19+
}
20+
21+
fn main() {
22+
foo();
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0720]: cannot resolve opaque type
2+
--> $DIR/recursive-generator.rs:5:13
3+
|
4+
LL | fn foo() -> impl Generator<Yield = (), Return = ()> {
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
6+
...
7+
LL | / || {
8+
LL | |
9+
LL | | let mut gen = Box::pin(foo());
10+
| | ------- generator captures itself here
11+
LL | |
12+
... |
13+
LL | | }
14+
LL | | }
15+
| |_____- returning here with type `[generator@$DIR/recursive-generator.rs:9:5: 9:7]`
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0720`.

tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ LL | fn closure_capture() -> impl Sized {
5353
...
5454
LL | / move || {
5555
LL | | x;
56+
| | - closure captures itself here
5657
LL | | }
5758
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]`
5859

@@ -64,6 +65,7 @@ LL | fn closure_ref_capture() -> impl Sized {
6465
...
6566
LL | / move || {
6667
LL | | &x;
68+
| | - closure captures itself here
6769
LL | | }
6870
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]`
6971

@@ -94,6 +96,7 @@ LL | fn generator_capture() -> impl Sized {
9496
LL | / move || {
9597
LL | | yield;
9698
LL | | x;
99+
| | - generator captures itself here
97100
LL | | }
98101
| |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]`
99102

@@ -114,6 +117,7 @@ LL | fn generator_hold() -> impl Sized {
114117
LL |
115118
LL | / move || {
116119
LL | | let x = generator_hold();
120+
| | - generator captures itself here
117121
LL | | yield;
118122
LL | | x;
119123
LL | | }

0 commit comments

Comments
 (0)