rust-lang / rust-lang/rust

Strange inference failure with `Arc::new_cyclic`

Open
#139,736 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-inference C-discussion T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the example in the playground's src/lib.rs with the reported rustc 1.88.0-nightly toolchain, focusing on Arc::<_>::new_cyclic and the closure's Weak type inference. Trace the behavior behind E0282 and E0609; done means explaining why the this.thing use changes inference and validating the resulting compiler behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.