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

Cycle when computing type of recursive opaque type #87850

Closed
LeSeulArtichaut opened this issue Aug 7, 2021 · 5 comments
Closed

Cycle when computing type of recursive opaque type #87850

LeSeulArtichaut opened this issue Aug 7, 2021 · 5 comments
Labels
-Zthir-unsafeck Unstable option: THIR unsafeck A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-typesystem Area: The type system C-bug Category: This is a bug. F-rustc_attrs Internal rustc attributes gated on the `#[rustc_attrs]` feature gate. I-cycle Issue: A query cycle occurred while none was expected T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@LeSeulArtichaut
Copy link
Contributor

I tried this code:

#![feature(rustc_attrs)]

#[rustc_layout_scalar_valid_range_start(1)]
struct NonZero<T>(T);

fn closure_ref_capture() -> NonZero<impl Sized> {
    let x = closure_ref_capture();
    unsafe { NonZero(move || { &x.0; }) }
}

rustc gives the following output:

error[E0391]: cycle detected when computing type of `closure_ref_capture::{opaque#0}`
 --> test.rs:6:37
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  |                                     ^^^^^^^^^^
  |
note: ...which requires borrow-checking `closure_ref_capture`...
 --> test.rs:6:1
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing `closure_ref_capture`...
 --> test.rs:6:1
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires processing MIR for `closure_ref_capture`...
 --> test.rs:6:1
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires building MIR for `closure_ref_capture`...
 --> test.rs:6:1
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires unsafety-checking `closure_ref_capture`...
 --> test.rs:8:33
  |
8 |     unsafe { NonZero(move || { &x.0; }) }
  |                                 ^^^
  = note: ...which requires computing whether `impl Sized` is freeze...
  = note: ...which requires evaluating trait selection obligation `impl Sized: std::marker::Freeze`...
  = note: ...which again requires computing type of `closure_ref_capture::{opaque#0}`, completing the cycle
note: cycle used when checking item types in top-level module
 --> test.rs:1:1
  |
1 | / #![feature(rustc_attrs)]
2 | |
3 | | #[rustc_layout_scalar_valid_range_start(1)]
4 | | struct NonZero<T>(T);
... |
8 | |     unsafe { NonZero(move || { &x.0; }) }
9 | | }
  | |_^

warning: function cannot return without recursing
 --> test.rs:6:1
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
7 |     let x = closure_ref_capture();
  |             --------------------- recursive call site
  |
  = note: `#[warn(unconditional_recursion)]` on by default
  = help: a `loop` may express intention better if this is on purpose

error[E0720]: cannot resolve opaque type
 --> test.rs:6:37
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  |                                     ^^^^^^^^^^ recursive opaque type
7 |     let x = closure_ref_capture();
8 |     unsafe { NonZero(move || { &x.0; }) }
  |              -------------------------- returning here with type `NonZero<[closure@test.rs:8:22: 8:39]>`

error: aborting due to 3 previous errors; 1 warning emitted

This affects both the MIR and the THIR unsafety checkers. However, since the code is obviously wrong and the relevant errors are still emitted, I'd expect this to be closed as wontfix.

Meta

rustc --version --verbose:

rustc 1.56.0-nightly (5ad7389bd 2021-08-06)
binary: rustc
commit-hash: 5ad7389bdd1abe7d2c6f73a233af1a7a69e96285
commit-date: 2021-08-06
host: x86_64-unknown-linux-gnu
release: 1.56.0-nightly
LLVM version: 12.0.1
@LeSeulArtichaut LeSeulArtichaut added A-typesystem Area: The type system T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. C-bug Category: This is a bug. -Zthir-unsafeck Unstable option: THIR unsafeck labels Aug 7, 2021
@danielhenrymantilla
Copy link
Contributor

Potentially related:

use Send as SomeAutoTrait;
macro_rules! SomeExistential {() => ( impl Sized )}

fn foo() -> SomeExistential!() {
    // check if `typeof![foo()] : SomeAutoTrait`
    let _: &dyn SomeAutoTrait = &foo();
}

@LeSeulArtichaut
Copy link
Contributor Author

@danielhenrymantilla Interestingly, the code you provided is a different cycle (it doesn't involve is_freeze checks). I think it looks more like #78649, and it might be a great MCVE for that issue which doesn't seem to have one.

Ultimately I think both issues have the same root cause, i.e. the type system and the MIR builder being dependent on each other. Maybe fixing #78649 will fix this issue as well.

@kornelski
Copy link
Contributor

kornelski commented Jan 19, 2022

I've ran into this in kornelski/cargo-deb@e814497 using rustc 1.60.0-nightly (ec4bcaa 2022-01-15) on macOS aarch64

and it's a weird case, because it only affects cargo fix --edition, but not any other command like cargo build, not even cargo fix --edition-idioms.

error[E0391]: cycle detected when computing when `manifest::CargoDeb` has a significant destructor
   --> src/manifest.rs:906:1
    |
906 | struct CargoDeb {
    | ^^^^^^^^^^^^^^^
    |
    = note: ...which immediately requires computing when `manifest::CargoDeb` has a significant destructor again
    = note: cycle used when computing whether `manifest::Cargo` has a significant drop

It doesn't like this:

struct CargoDeb {
    pub variants: Option<HashMap<String, CargoDeb>>,
}

It compiles if I change it to:

struct CargoDeb {
    pub variants: Option<HashMap<String, Box<CargoDeb>>>,
}

but given the odd nature of this bug, that may just be a coincidence.

@LeSeulArtichaut
Copy link
Contributor Author

@kornelski This is #92725, you can look there for details. Thanks anyway for the report.

@workingjubilee workingjubilee added the F-rustc_attrs Internal rustc attributes gated on the `#[rustc_attrs]` feature gate. label Mar 14, 2023
@syvb
Copy link
Contributor

syvb commented Jan 31, 2024

I can't reproduce this with the THIR unsafety checker (which is the default since #117673) on recent nightlies - I think this issue should be closed. The only error I get is (ignoring warnings):

error[E0720]: cannot resolve opaque type
 --> /tmp/a.rs:6:37
  |
6 | fn closure_ref_capture() -> NonZero<impl Sized> {
  |                                     ^^^^^^^^^^ recursive opaque type
7 |     let x = closure_ref_capture();
8 |     unsafe { NonZero(move || { &x.0; }) }
  |              --------------------------
  |              |                  |
  |              |                  closure captures itself here
  |              returning here with type `NonZero<{closure@/tmp/a.rs:8:22: 8:29}>`

@oli-obk oli-obk closed this as completed Jan 31, 2024
@fmease fmease added the I-cycle Issue: A query cycle occurred while none was expected label Jan 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
-Zthir-unsafeck Unstable option: THIR unsafeck A-impl-trait Area: `impl Trait`. Universally / existentially quantified anonymous types with static dispatch. A-typesystem Area: The type system C-bug Category: This is a bug. F-rustc_attrs Internal rustc attributes gated on the `#[rustc_attrs]` feature gate. I-cycle Issue: A query cycle occurred while none was expected T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

7 participants