Skip to content

Strange inference failure with Arc::new_cyclic #139736

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

Open
Sky9x opened this issue Apr 13, 2025 · 3 comments
Open

Strange inference failure with Arc::new_cyclic #139736

Sky9x opened this issue Apr 13, 2025 · 3 comments
Labels
A-inference Area: Type inference C-discussion Category: Discussion or questions that doesn't represent real issues. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@Sky9x
Copy link
Contributor

Sky9x commented Apr 13, 2025

I tried this code (playground):

#![allow(unused)]

use std::sync::Arc;
use tokio_util::task::AbortOnDropHandle;

pub struct Foo {
    thing: Thing,
    task: AbortOnDropHandle<()>,
}

impl Foo {
    pub fn new() -> Arc<Self> {
        // Fix 1: replace `<_>` with `<Self>`
        Arc::<_>::new_cyclic(|weak| {
            let weak = weak.clone();
            let handler = async move {
                async { /* ... */ }.await; // waiting for some event

                if let Some(this) = weak.upgrade() {
                    // "Fix" 2: comment out this line
                    this.thing.do_thing();
                }
            };

            Foo {
                thing: Thing,
                task: AbortOnDropHandle::new(tokio::spawn(handler)),
            }
        })
    }
}

struct Thing;

impl Thing {
    fn do_thing() { unimplemented!() }
}

I expected to see this happen: It compiles

Instead, this happened: It does not compile

I find it very strange the type inference is unable to figure out that
a. new_cyclic returns an Arc<Self>
b. the closure returns a Foo

I find it even stranger that commenting out the line where the inner value is used ("Fix" 2) makes it compile.

Compiler Error:

   Compiling playground v0.0.1 (/playground)
error[E0282]: type annotations needed for `&std::sync::Weak<_>`
  --> src/lib.rs:14:31
   |
14 |         Arc::<_>::new_cyclic(|weak| {
   |                               ^^^^
...
21 |                     this.thing.do_thing();
   |                     ---------- type must be known at this point
   |
help: consider giving this closure parameter an explicit type, where the type for type parameter `T` is specified
   |
14 |         Arc::<_>::new_cyclic(|weak: &std::sync::Weak<T>| {
   |                                   +++++++++++++++++++++

error[E0609]: no field `thing` on type `Arc<_>`
  --> src/lib.rs:21:26
   |
21 |                     this.thing.do_thing();
   |                          ^^^^^ unknown field

Some errors have detailed explanations: E0282, E0609.
For more information about an error, try `rustc --explain E0282`.
error: could not compile `playground` (lib) due to 2 previous errors

rustc version:

rustc 1.88.0-nightly (9ffde4b08 2025-04-12)
binary: rustc
commit-hash: 9ffde4b089fe8e43d5891eb517001df27a8443ff
commit-date: 2025-04-12
host: x86_64-unknown-linux-gnu
release: 1.88.0-nightly
LLVM version: 20.1.2
@Sky9x Sky9x added the C-bug Category: This is a bug. label Apr 13, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 13, 2025
@Sky9x

This comment has been minimized.

@rustbot rustbot added the A-inference Area: Type inference label Apr 13, 2025
@compiler-errors
Copy link
Member

compiler-errors commented Apr 13, 2025

I find it very strange the type inference is unable to figure out [...]

We check the type of the closure before unifying the return type with the value of the expression. So by the time we're type checking the closure, we know nothing about the pointee type of the argument weak: &Weak<_> in the closure.

By the time we do the field access this.thing we need to know the type of this. This is typically the source of E0282 errors, which stem from the order dependence of inference in Rust's type system.

Notably, this happens before we've checked the return type of the closure either, so we still haven't constrained the type of the pointee of the Arc.

I find it even stranger that commenting out the line where the inner value is used ("Fix" 2) makes it compile.

This removes the requirement that we know a values' type eagerly.


All that above was just me explaining why this is an error today; I don't believe this is possible to fix, at least not soon, though.

As a side note, #139423 will fix this erroneous extra error:

error[E0609]: no field `thing` on type `Arc<_>`
  --> src/lib.rs:21:26
   |
21 |                     this.thing.do_thing();
   |                          ^^^^^ unknown field

It's not yet present on the nightly toolchain on playground, tho.

@Sky9x
Copy link
Contributor Author

Sky9x commented Apr 15, 2025

Interesting. Thanks for the explanation.

@jieyouxu jieyouxu added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. C-discussion Category: Discussion or questions that doesn't represent real issues. and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. C-bug Category: This is a bug. labels May 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-inference Area: Type inference C-discussion Category: Discussion or questions that doesn't represent real issues. 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

4 participants