clash-compiler icon indicating copy to clipboard operation
clash-compiler copied to clipboard

Custom bit representations fail for single-constructor data types

Open kleinreact opened this issue 11 months ago • 2 comments

As already noted in #2949: custom bit representations fail for data types with only a single constructor, e.g.,

data T = T0 Bool
{-# ANN module (DataReprAnn $(liftQ [t|T|]) 1
  [ConstrRepr 'T0 0b0 0b0 [0b1]]) #-}

causes Clash to produce

<no location info>: error:
    Clash error call:
    Unexpected HWType: Bool
    CallStack (from HasCallStack):
      error, called at src/Clash/Netlist/Util.hs:316:10 in clash-lib-1.9.0-inplace:Clash.Netlist.Util
      convertToCustomRepr, called at src/Clash/Netlist/Util.hs:356:8 in clash-lib-1.9.0-inplace:Clash.Netlist.Util

The utilized inner type does not matter. It can be Int, Bool, or something else. Clash always fails in this case.

Thanks to @DigitalBrains1 for making clear that this is a bug.

kleinreact avatar May 02 '25 16:05 kleinreact

Data types with only a single constructor and field are reduced to just the field type here

https://github.com/clash-lang/clash-compiler/blob/4384800decf44ba51fc1fd083ff69691f0350ba1/clash-lib/src/Clash/Netlist/Util.hs#L472-L473

which then eventually gets passed to convertToCustomRepr checking that the number of constructor fields in the data representation matches with the custom one

https://github.com/clash-lang/clash-compiler/blob/4384800decf44ba51fc1fd083ff69691f0350ba1/clash-lib/src/Clash/Netlist/Util.hs#L286

However, nConstrs and cs both expect to only see sum and product types, which is why nConstrs already fails.

https://github.com/clash-lang/clash-compiler/blob/4384800decf44ba51fc1fd083ff69691f0350ba1/clash-lib/src/Clash/Netlist/Util.hs#L298-L316

Is there a reason to not return a singleton product type in mkADT for a single constructor and field?

kleinreact avatar May 02 '25 18:05 kleinreact

I’ve forgotten the original reason, maybe some code archeology can recover it from the commit messages. If I were to have a guess it is that newtypes sometimes aren’t “constructed”, but “cast” and this was messing up the VHDL backend (creating VHDL that wouldn’t typecheck). And at the time “filtering” single field product types was the path of least resistance.

christiaanb avatar May 03 '25 06:05 christiaanb