Skip to content

Deref to type that is also a Receiver to the original type creates an infinite cycle #139394

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

Closed
tmandry opened this issue Apr 4, 2025 · 5 comments
Labels
C-discussion Category: Discussion or questions that doesn't represent real issues. F-arbitrary_self_types `#![feature(arbitrary_self_types)]`

Comments

@tmandry
Copy link
Member

tmandry commented Apr 4, 2025

Let's say I define a transparent receiver type like this:

#[repr(transparent)]
struct CRef<T> {
    inner: T,
}

impl<T> Receiver for CRef<T> {
    type Target = T;
}

And then a type which allows "viewing" itself as a &CRef<T> when what you have is a &T:

#[repr(C)]
struct Flag(i32);

impl Deref for Flag {
    type Target = CRef<Flag>;
    fn deref(&self) -> &Self::Target {
        unsafe { &*(self as *const _ as *const CRef<Self>) }
    }
}

Then given this:

impl Flag {
    fn get(self: &CRef<Self>) -> i32 { 42 }
}

fn main() {
    let flag = Flag(0);
    assert_eq!(flag.get(), 42);
}

I expect flag.get() to mean something like

let flagcr: &CRef<Flag> = <Flag as Deref>::deref(&flag);
Flag::get(flagcr)

but instead I got

error[E0055]: reached the recursion limit while auto-dereferencing `CRef<Flag>`
  --> src/main.rs:32:21
   |
32 |     assert_eq!(flag.get(), 42);
   |                     ^^^ deref recursion limit reached
   |
   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`playground`)

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=e3e560589bf664d37a489d798f41cca5

It's possible this is somehow correct and there's no way to do what I'm trying to do, but if it is I don't see why.

@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 4, 2025
@tmandry tmandry added the F-arbitrary_self_types `#![feature(arbitrary_self_types)]` label Apr 4, 2025
@compiler-errors
Copy link
Member

This is not a bug. This produces a receiver chain that goes Flag -> CRef<Flag> -> Flag -> ... which is an infinite set of types.

@tmandry
Copy link
Member Author

tmandry commented Apr 22, 2025

@compiler-errors I see how that's an infinite chain, but I don't see how it's an infinite set. There are only two types. Are you saying it's the interaction with autoref that produces an infinite set of types?

@compiler-errors
Copy link
Member

Autoderef doesn't deduplicate infinite chains of types if they have closed cycles.

This could be hacked around, but I'd probably discourage it, since this would be problematic, for example, as soon as we had things like type and lifetime variables in the types, since it's pretty easy to construct a chain of types that differ only by inference variables which are yet unresolved.

@compiler-errors
Copy link
Member

All autoderef does is repeatedly apply <TY as Receiver>::Target and normalize that type. So to autoderef there are an infinite set of types, since it doesn't care if these types have any sort of reoccurrence relationship.

@tmandry
Copy link
Member Author

tmandry commented Apr 23, 2025

Ok, thanks for answering my questions!

To summarize, it would be difficult to do cycle detection because of the possible presence of type variables. Maybe some kind of canonicalization could work if we had to solve this. But we don't really: The Deref impl is a hack to simulate a form of custom autoref, which could be modeled in a more first-class way, albeit only with new language features.

@tmandry tmandry closed this as not planned Won't fix, can't repro, duplicate, stale Apr 23, 2025
@saethlin saethlin added 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. labels Apr 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-discussion Category: Discussion or questions that doesn't represent real issues. F-arbitrary_self_types `#![feature(arbitrary_self_types)]`
Projects
None yet
Development

No branches or pull requests

4 participants