Skip to content

[Bug] Compiler crash (AssertionError) on a design class with a default value in a second curried parameter list #456

Description

@soronpo

Translating demos/mandelbrot/mandelbrot.sv from projf-explore
(https://github.com/projf/projf-explore) to DFHDL. The Verilog module has a
parameter list where one parameter's default depends on an earlier one:

module mandelbrot #(
    parameter FP_WIDTH=25,
    parameter FP_INT=4,
    parameter ITER_MAX=255,
    parameter ITERW=$clog2(ITER_MAX+1)  // depends on ITER_MAX
    ) ( ... );

A single DFHDL parameter list does not allow a later parameter's default to
reference an earlier one by simple name (confirmed this is also true in plain
Scala 3, not DFHDL-specific: class Probe2(val a: Int = 5, val b: Int = a + 1)
fails to compile with Not found: a). The standard Scala workaround for this
is a second (curried) parameter list, e.g. class Foo(a: Int)(b: Int = a + 1).

That workaround crashes the DFHDL compiler. The crash reproduces even with a
default that does not reference the first list at all — any DFHDL design
class with two curried parameter lists where the second list has a default
value crashes.

Minimal reproduction

import dfhdl.*
// two curried DFHDL param lists, default value on 2nd list param,
// no cross-reference between the lists
class Probe7(val A: Int <> CONST = 4)(val B: Int <> CONST = 8) extends EDDesign:
  val o = UInt(B) <> OUT
  o <> 0

Run with:

scala run src/ --scala 3.8.4 \
  --dep "io.github.dfianthdl::dfhdl::$V" \
  --compiler-plugin "io.github.dfianthdl:::dfhdl-plugin::$V" \
  -O -deprecation -M Probe7 -- --nocache commit

Expected behavior

Either a successful compile (curried parameter lists are ordinary Scala and
should be supported), or a clear DFHDL-level diagnostic saying curried
parameter lists / defaults in a non-first parameter list are unsupported.

Actual behavior

Internal compiler crash (not a normal DFHDL elaboration error):

[90mCompiling project (Scala 3.8.4, JVM (25))[0m
[90mError compiling project (Scala 3.8.4, JVM (25))[0m
Error: java.lang.AssertionError: assertion failed: bad adapt for Probe7.$lessinit$greater$default$2: (A: dfhdl.core.DFVal): dfhdl.core.DFVal
	at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:10)
	at dotty.tools.dotc.transform.Erasure$Boxing$.adaptToType(Erasure.scala:389)
	at dotty.tools.dotc.transform.Erasure$Typer.adapt(Erasure.scala:1059)
	at dotty.tools.dotc.typer.Typer.typed(Typer.scala:4017)
	...

The assertion message oddly names the first list's parameter (A) even
though the crash is triggered by the second list's default value having any
default at all (tested with = 8, a literal with no reference to A) — this
mislabeling may itself be a clue to the root cause (something in how the
plugin synthesizes/threads the $default$N accessor across parameter-list
boundaries).

Also reproduces with the original motivating case, where the second list's
default genuinely references the first list's parameter:

import dfhdl.*
class Probe4(val ITER_MAX: Int <> CONST = 255)(
    val ITERW: Int <> CONST = clog2(ITER_MAX + 1)
) extends EDDesign:
  val o = UInt(ITERW) <> OUT
  o <> 0
```//same crash, message: "bad adapt for Probe4.$lessinit$greater$default$2: (ITER_MAX: dfhdl.core.DFVal): dfhdl.core.DFVal"

Two curried parameter lists with **no** default value on the second list
compile fine:

```scala
import dfhdl.*
class Probe6(val A: Int <> CONST)(val B: Int <> CONST) extends EDDesign:
  val o = UInt(B) <> OUT
  o <> 0

This one compiles successfully (fails only later, expectedly, because no
AppMode default exists for a class requiring constructor args to run
without CLI arguments).

DFHDL version

v0.22.0+39-03afffb1-SNAPSHOT

Workaround used

Converted the dependent parameter into a plain derived val in the design
body instead of a constructor parameter (losing external overridability of
that one parameter, which was the only way to keep the translation
compiling):

class mandelbrot(
    val FP_WIDTH: Int <> CONST = 25,
    val FP_INT: Int <> CONST = 4,
    val ITER_MAX: Int <> CONST = 255
) extends EDDesign:
  val ITERW = clog2(ITER_MAX + 1)
  ...

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