Skip to content

[Bug] Design class literally named top fails with unhelpful "Cyclic reference involving class top", no hint of the real cause #458

Description

@soronpo

Context

Translating HOG_fpga/src/top.v (Mahmoud-geberty/HOG_fpga), whose Verilog module is named top (an extremely common convention for a design's top-level module). The equivalent knowledge-gap ticket dfhdl_by_agents#82 already documents that a DFHDL design class named top collides with DFHDL's internal @top annotation/detection mechanism, and that renaming the class is the only known workaround (@targetName cannot help either, since it is rejected on a top-level class — DFHDL#454). This ticket is the companion bug report for the error message itself, which #82 did not file separately.

Minimal reproduction (verified against 0.22.0+39-03afffb1-SNAPSHOT)

import dfhdl.*

class top extends EDDesign:
  val i = Bit <> IN
  val o = Bit <> OUT
  o <> i
scala run src/ --scala 3.8.4 \
  --dep "io.github.dfianthdl::dfhdl::$V" \
  --compiler-plugin "io.github.dfianthdl:::dfhdl-plugin::$V" \
  -O -deprecation -M top -- --nocache commit

Full verbatim error text

[error] ./src/top.scala:3:7
[error] Cyclic reference involving class top
[error] 
[error]  Run with -explain-cyclic for more details.
[error] class top extends EDDesign:
[error]       ^
Warning: 1 error found

With -explain-cyclic added, the only extra detail is:

[error] The error occurred while trying to compute the signature of class top
[error]   which required to compute the signature of class top

Confirmed fix

Renaming the class only (identical body, identical file otherwise) compiles cleanly:

import dfhdl.*

class topOk extends EDDesign:
  val i = Bit <> IN
  val o = Bit <> OUT
  o <> i

This is the only variable changed between the failing and succeeding runs, isolating the cause to the identifier top itself, not anything about the class body.

Where I expected the error to point vs. where it pointed

I expected either: (a) a normal Scala compile error about the body (there is nothing wrong with the body), or (b) if this is truly a reserved-name collision, a message naming the collision (e.g. "the name top is reserved for the internal @top mechanism; rename the design class"). Instead the position and message both describe a self-referential signature computation ("Cyclic reference ... which required to compute the signature of class top"), which reads as if the class's own member declarations form a genuine dependency cycle. Nothing in the class body is self-referential — the file is 5 lines with no forward references at all.

What I thought the message meant vs. what was actually wrong

I initially assumed I had introduced a real forward-reference cycle (e.g. a val in the class referencing another val defined later, or a parameter default depending on a sibling parameter — a distinct, real limitation I hit and confirmed separately, filed as dfhdl_by_agents#115). I spent several compile/bisect iterations removing and re-adding class members (parameters, port declarations, child instantiations, a multi-branch if/else body) looking for a genuine self-reference in the body, all while the true cause was the bare identifier top used as the class name, unrelated to anything in the body. Only exhaustive bisection — reducing the file to 5 lines and then renaming just the class — revealed the real cause.

Suggested clearer message

Since DFHDL already detects and auto-applies its own @top-related mechanism for the class name top (per dfhdl_by_agents#82), the compiler plugin has enough information at this point to name the actual conflict, e.g.:

error: the design class name `top` conflicts with DFHDL's internal `@top` mechanism.
Rename the class (the generated module name can be restored with `@targetName`,
except this is not currently supported for top-level classes — see DFHDL#454).

That would turn a multi-iteration debugging session into an immediate, actionable fix.

Cross-references

  • dfhdl_by_agents#82 — the knowledge-gap side (docs should list top as a reserved name).
  • DFHDL#454@targetName rejected on a top-level design class, which forecloses the natural "keep the class name different, restore the module name" workaround.

Version

0.22.0+39-03afffb1-SNAPSHOT

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions