Cycle detected when const checking? Yes! The cycle is on purpose!

I'm writing a compiler. I'm trying to represent the AST using Rust consts, where each node holds 'static references to all its descendent nodes. Since this is actually an abstract syntax graph and not a tree, there are cycles. I'm doing this on purpose, but Rust doesn't like it.

Simple reproducer:

struct Node {
    name: &'static str,
    next: Option<&'static Node>,
}

const A: Node = Node { name: "A", next: Some(&B) };
const B: Node = Node { name: "B", next: Some(&A) };

The entire error seen on the playground:

error[E0391]: cycle detected when const checking `A`
 --> src/lib.rs:6:47
  |
6 | const A: Node = Node { name: "A", next: Some(&B) };
  |                                               ^
  |
note: ...which requires const checking `B`...
 --> src/lib.rs:7:47
  |
7 | const B: Node = Node { name: "B", next: Some(&A) };
  |                                               ^
  = note: ...which again requires const checking `A`, completing the cycle
note: cycle used when processing `A`
 --> src/lib.rs:6:1
  |
6 | const A: Node = Node { name: "A", next: Some(&B) };
  | ^^^^^^^^^^^^^^^^^^^^

For more information about this error, try `rustc --explain E0391`.

I'm hoping there's some easy fix for this, but I'm not holding my breath. The nodes already have unique names, so it's trivial for me to use a HashMap or some such to break the cycle. I was just hoping I wouldn't have to.

Interestingly, rustc --explain E0391 isn't quite applicable to this situation:

A type dependency cycle has been encountered.

Erroneous code example:

trait FirstTrait : SecondTrait {

}

trait SecondTrait : FirstTrait {

}

The previous example contains a circular dependency between two traits: FirstTrait depends on SecondTrait which itself depends on FirstTrait.

The best way to think about const is that the value is inlined wherever it's used. So in a way, you just made a mutually recursive function. The way to avoid this is quite simple, thankfully! Use static instead of const, and then you're guaranteed to only have a single instance, which the compiler can handle without issue.

3 Likes

Oh, excellent. That does, indeed, work.

Thanks so much!

(Edit to add:) Ironically, the language I'm compiling has similar semantics for const, and would have encountered the same problem.