Skip to content

[Bug] Referencing a sibling design class named top still fails post-#465, with a new, unrelated-looking error #482

Description

@soronpo

Context

DFHDL#458 / dfhdl_by_agents#82 documented that a design class named top collides with
DFHDL's internal @top annotation, producing an unhelpful "Cyclic reference involving class
top" at the declaration site. #458 says this was "Fixed in #465".

Translating HOG_fpga/src/top_wrapper.v (run hog-1), which instantiates a child module also
named top (HOG_fpga/src/top.v), I confirmed the declaration-site fix: class top extends EDDesign now compiles fine on its own against current HEAD. But a second, distinct
collision remains when another file references it with new top(...) — with a completely
different, and equally unhelpful, error.

Minimal reproduction (verified against 0.22.0+106-847a1a10-SNAPSHOT)

src/top.scala:

import dfhdl.*

class top(
    val WIDTH: Int <> CONST = 8
) extends EDDesign:
  val clk, rst = Bit <> IN
  val din = Bits(WIDTH) <> IN
  val dout = Bits(WIDTH) <> OUT
  dout <> din
end top

src/Wrapper.scala:

import dfhdl.*

class Wrapper extends EDDesign:
  val clk, rst = Bit <> IN
  val din = Bits(8) <> IN
  val dout = Bits(8) <> OUT

  val u_top = new top(WIDTH = 8)
  u_top.clk <> clk
  u_top.rst <> rst
  u_top.din <> din
  u_top.dout <> dout
end Wrapper
scala run src/ --scala 3.8.4 \
  --dep "io.github.dfianthdl::dfhdl::$V" \
  --compiler-plugin "io.github.dfianthdl:::dfhdl-plugin::$V" \
  -O -deprecation -M Wrapper -- --nocache commit

Full verbatim error text

[error] ./src/Wrapper.scala:8:23
[error] constructor top in class top: (genMain: Boolean)
[error]   (using annot: dfhdl.internals.AnnotatedWith[dfhdl.top, Any])
[error]     (using
[error]       elaborationOptions: dfhdl.options.ElaborationOptions.Defaults[annot.Out],
[error]       compilerOptions: dfhdl.options.CompilerOptions.Defaults[annot.Out],
[error]       printerOptions: dfhdl.options.PrinterOptions.Defaults[annot.Out],
[error]       linterOptions: dfhdl.options.LinterOptions.Defaults[annot.Out],
[error]       simulatorOptions: dfhdl.options.SimulatorOptions.Defaults[annot.Out],
[error]       appOptions: dfhdl.options.AppOptions.Defaults[annot.Out],
[error]       builderOptions: dfhdl.options.BuilderOptions.Defaults[annot.Out],
[error]       programmerOptions: dfhdl.options.ProgrammerOptions.Defaults[annot.Out]):
[error]       dfhdl.top does not have a parameter WIDTH
[error]   val u_top = new top(WIDTH = 8)
[error]                       ^^^^^^^^^^
[error] ./src/Wrapper.scala:8:15
[error] missing argument for parameter genMain of constructor top in class top: (genMain: Boolean)
[error]   (using annot: dfhdl.internals.AnnotatedWith[dfhdl.top, Any])
[error]   ... (same using clauses as above)
[error]       dfhdl.top
[error]   val u_top = new top(WIDTH = 8)
[error]               ^^^^^^^^^^^^^^^^^^
Warning: 2 errors found

import dfhdl.* in Wrapper.scala is bringing dfhdl.top (the built-in annotation class,
constructor (genMain: Boolean)) into scope, and it wins name resolution over the sibling
top-level class top defined in top.scala in the same project. Nothing in the message says
"name collision" or mentions the annotation by name in a way that explains what happened;
it reads as if the user's own class top suddenly has a genMain: Boolean constructor
parameter and no WIDTH parameter, which is not true of any code the user wrote.

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

Expected either a normal successful compile (the class and its usage are both syntactically
and semantically correct DFHDL), or, if this is genuinely a reserved-name collision, a message
saying so explicitly. Instead it reports a constructor signature — (genMain: Boolean) — that
does not appear anywhere in the 6-line top.scala above, with no indication that the
identifier resolved to a completely different, DFHDL-internal top.

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

First reading suggested class top's own constructor was somehow malformed or that DFHDL
requires every top-level design to declare a genMain: Boolean parameter — neither is true.
Only recognizing dfhdl.top does not have a parameter WIDTH as a reference to a different
type than the one just declared revealed the actual cause: the wildcard import silently
shadows a same-named sibling design.

Confirmed fix

Shadowing the built-in annotation out of the wildcard import resolves top to the local class:

import dfhdl.{top => _, *}

With only this one-line change to Wrapper.scala's import, the same file compiles cleanly and
elaborates correctly.

Suggested clearer message

Since the plugin's TopAnnotPhase already knows about @top/dfhdl.top, and the position is a
new <ident>(...) call, it should be feasible to detect "the resolved type is dfhdl.top, but
a same-named user design class also exists in this compilation," and emit something like:

error: `top` resolved to the built-in `dfhdl.top` annotation, not your design class `top`
(defined in top.scala). The wildcard import `import dfhdl.*` gives the built-in name priority.
Shadow it explicitly: `import dfhdl.{top => _, *}`.

Cross-references

  • DFHDL#458 — the declaration-site "Cyclic reference" variant, closed as fixed by #465.
    This ticket is the residual use-site variant that #465 did not cover.
  • DFHDL#454@targetName rejected on a top-level design class, which forecloses renaming
    the class while keeping the emitted module name top.
  • dfhdl_by_agents#82 — the knowledge-gap side; its documented workaround ("rename the class
    to e.g. hog_top") is now the wrong advice for anyone doing a literal translation where the
    generated module name must stay top to match the gold Verilog — the shadow-import above is
    the workaround that preserves the class name. Filing a follow-up knowledge-gap ticket
    separately.

Version

0.22.0+106-847a1a10-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