Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Label closure captures/generator locals that make opaque types recursive #106578

Merged
merged 1 commit into from
Jan 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions compiler/rustc_hir_analysis/src/check/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1391,11 +1391,15 @@ fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed
///
/// If all the return expressions evaluate to `!`, then we explain that the error will go away
/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder.
fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> ErrorGuaranteed {
fn opaque_type_cycle_error(
tcx: TyCtxt<'_>,
opaque_def_id: LocalDefId,
span: Span,
) -> ErrorGuaranteed {
let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");

let mut label = false;
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
let typeck_results = tcx.typeck(def_id);
if visitor
.returns
Expand Down Expand Up @@ -1431,28 +1435,71 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> E
.filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
{
struct OpaqueTypeCollector(Vec<DefId>);
#[derive(Default)]
struct OpaqueTypeCollector {
opaques: Vec<DefId>,
closures: Vec<DefId>,
}
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
self.0.push(def);
self.opaques.push(def);
ControlFlow::Continue(())
}
ty::Closure(def_id, ..) | ty::Generator(def_id, ..) => {
self.closures.push(def_id);
t.super_visit_with(self)
}
_ => t.super_visit_with(self),
}
}
}
let mut visitor = OpaqueTypeCollector(vec![]);

let mut visitor = OpaqueTypeCollector::default();
ty.visit_with(&mut visitor);
for def_id in visitor.0 {
for def_id in visitor.opaques {
let ty_span = tcx.def_span(def_id);
if !seen.contains(&ty_span) {
err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
seen.insert(ty_span);
}
err.span_label(sp, &format!("returning here with type `{ty}`"));
}

for closure_def_id in visitor.closures {
let Some(closure_local_did) = closure_def_id.as_local() else { continue; };
let typeck_results = tcx.typeck(closure_local_did);

let mut label_match = |ty: Ty<'_>, span| {
for arg in ty.walk() {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
&& let ty::Alias(ty::Opaque, ty::AliasTy { def_id: captured_def_id, .. }) = *ty.kind()
&& captured_def_id == opaque_def_id.to_def_id()
{
err.span_label(
span,
format!(
"{} captures itself here",
tcx.def_kind(closure_def_id).descr(closure_def_id)
),
);
}
}
};

// Label any closure upvars that capture the opaque
for capture in typeck_results.closure_min_captures_flattened(closure_local_did)
{
label_match(capture.place.ty(), capture.get_path_span(tcx));
}
// Label any generator locals that capture the opaque
for interior_ty in
typeck_results.generator_interior_types.as_ref().skip_binder()
{
label_match(interior_ty.ty, interior_ty.span);
}
}
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions tests/ui/impl-trait/recursive-generator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#![feature(generators, generator_trait)]

use std::ops::{Generator, GeneratorState};

fn foo() -> impl Generator<Yield = (), Return = ()> {
//~^ ERROR cannot resolve opaque type
//~| NOTE recursive opaque type
//~| NOTE in this expansion of desugaring of
|| {
//~^ NOTE returning here
let mut gen = Box::pin(foo());
//~^ NOTE generator captures itself here
let mut r = gen.as_mut().resume(());
while let GeneratorState::Yielded(v) = r {
yield v;
r = gen.as_mut().resume(());
}
}
}

fn main() {
foo();
}
19 changes: 19 additions & 0 deletions tests/ui/impl-trait/recursive-generator.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
error[E0720]: cannot resolve opaque type
--> $DIR/recursive-generator.rs:5:13
|
LL | fn foo() -> impl Generator<Yield = (), Return = ()> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ recursive opaque type
...
LL | / || {
LL | |
LL | | let mut gen = Box::pin(foo());
| | ------- generator captures itself here
LL | |
... |
LL | | }
LL | | }
| |_____- returning here with type `[generator@$DIR/recursive-generator.rs:9:5: 9:7]`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0720`.
4 changes: 4 additions & 0 deletions tests/ui/impl-trait/recursive-impl-trait-type-indirect.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ LL | fn closure_capture() -> impl Sized {
...
LL | / move || {
LL | | x;
| | - closure captures itself here
LL | | }
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]`

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

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

Expand All @@ -114,6 +117,7 @@ LL | fn generator_hold() -> impl Sized {
LL |
LL | / move || {
LL | | let x = generator_hold();
| | - generator captures itself here
LL | | yield;
LL | | x;
LL | | }
Expand Down