Label closure captures/generator locals that make opaque types recursive
This commit is contained in:
parent
0726909f6d
commit
8742fd9c85
@ -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
|
/// 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.
|
/// 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 err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
|
||||||
|
|
||||||
let mut label = false;
|
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);
|
let typeck_results = tcx.typeck(def_id);
|
||||||
if visitor
|
if visitor
|
||||||
.returns
|
.returns
|
||||||
@ -1431,21 +1435,30 @@ 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_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t)))
|
||||||
.filter(|(_, ty)| !matches!(ty.kind(), ty::Never))
|
.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 {
|
impl<'tcx> ty::visit::TypeVisitor<'tcx> for OpaqueTypeCollector {
|
||||||
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
match *t.kind() {
|
match *t.kind() {
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
|
||||||
self.0.push(def);
|
self.opaques.push(def);
|
||||||
ControlFlow::Continue(())
|
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),
|
_ => t.super_visit_with(self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut visitor = OpaqueTypeCollector(vec![]);
|
|
||||||
|
let mut visitor = OpaqueTypeCollector::default();
|
||||||
ty.visit_with(&mut visitor);
|
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);
|
let ty_span = tcx.def_span(def_id);
|
||||||
if !seen.contains(&ty_span) {
|
if !seen.contains(&ty_span) {
|
||||||
err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
|
err.span_label(ty_span, &format!("returning this opaque type `{ty}`"));
|
||||||
@ -1453,6 +1466,40 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
|||||||
}
|
}
|
||||||
err.span_label(sp, &format!("returning here with type `{ty}`"));
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
tests/ui/impl-trait/recursive-generator.rs
Normal file
23
tests/ui/impl-trait/recursive-generator.rs
Normal file
@ -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
tests/ui/impl-trait/recursive-generator.stderr
Normal file
19
tests/ui/impl-trait/recursive-generator.stderr
Normal file
@ -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`.
|
@ -53,6 +53,7 @@ LL | fn closure_capture() -> impl Sized {
|
|||||||
...
|
...
|
||||||
LL | / move || {
|
LL | / move || {
|
||||||
LL | | x;
|
LL | | x;
|
||||||
|
| | - closure captures itself here
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]`
|
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 35:12]`
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ LL | fn closure_ref_capture() -> impl Sized {
|
|||||||
...
|
...
|
||||||
LL | / move || {
|
LL | / move || {
|
||||||
LL | | &x;
|
LL | | &x;
|
||||||
|
| | - closure captures itself here
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]`
|
| |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 43:12]`
|
||||||
|
|
||||||
@ -94,6 +96,7 @@ LL | fn generator_capture() -> impl Sized {
|
|||||||
LL | / move || {
|
LL | / move || {
|
||||||
LL | | yield;
|
LL | | yield;
|
||||||
LL | | x;
|
LL | | x;
|
||||||
|
| | - generator captures itself here
|
||||||
LL | | }
|
LL | | }
|
||||||
| |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]`
|
| |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 61:12]`
|
||||||
|
|
||||||
@ -114,6 +117,7 @@ LL | fn generator_hold() -> impl Sized {
|
|||||||
LL |
|
LL |
|
||||||
LL | / move || {
|
LL | / move || {
|
||||||
LL | | let x = generator_hold();
|
LL | | let x = generator_hold();
|
||||||
|
| | - generator captures itself here
|
||||||
LL | | yield;
|
LL | | yield;
|
||||||
LL | | x;
|
LL | | x;
|
||||||
LL | | }
|
LL | | }
|
||||||
|
Loading…
Reference in New Issue
Block a user