chipsalliance / chipsalliance/chisel

[Feature Request] expose outer class of `ChiselEnum#Type`

Open
#4,034 0 comments 1 reaction 0 assignees View on GitHub
Dominant language
Scala
Stars
4.8k
Forks
658
Avg merge
18h 59m
Merged PRs (30d)
14

Description

**Type of issue**: Feature Request

**Is your feature request related to a problem? Please describe.**

I'm extending `ChiselEnum` for some features.

An inner class in the `ChiselEnum` is bad for extending. It's not possible to override an inner class. Expose the outer class might not be a good solution, but it's effective for me.

**Describe the solution you'd like**

https://github.com/chipsalliance/chisel/blob/17398c1657705a0733a1768f0e84672c39962327/core/src/main/scala/chisel3/ChiselEnum.scala#L236

Maybe change to `class Type(val factor: ChiselEnum) extends EnumType(this)`

**Additional context**

It's possible to use `implict class` to extend `ChiselEnum#Type`, but we can't apply implict conversion automatically at runtime.

For example:

```scala
trait Default {
def default: Data
}

abstract class ChiselEnumDefault extends ChiselEnum {
def default: Type
implicit class TypeExtension(ty: Type) extends Default {
override def default = ChiselEnumDefault.this.default
}
}

object E extends ChiselEnumDefault {
val a, b, c = Value
override def default = a
}

val e1 = E()
val foo = e1.default
// ^ E.a
val e2 = E().asInstanceOf[Data]
val bar = e2.asInstanceOf[Default].default
// ^ runtime exception class chisel3.ChiselEnum$Type cannot be cast to class Default
```

**What is the use case for implementing this feature?**

Here are some examples:

```scala
object Extension {
implicit class ChiselEnumExtension[T <: ChiselEnum](value: T#Type) {
def is(select: T => Data) = {
val field = value.getClass.getField("$outer")
select(field.get(value).asInstanceOf[T]) === value
}
}
}
```

So we can use `foo.is(Foo.bar)` instead of `foo === Foo.bar`. It's shorter.

```scala
abstract class EnumDefault extends ChiselEnum {
def default: Type
}

object Extension {
implicit class TypeExtension(ty: EnumDefault#Type) {
def default = {
val field = ty.getClass.getField("$outer")
field.get(ty).asInstanceOf[EnumDefault].default
}
}
}

object AluOp extends EnumDefault {
val n, add, sub = Value
def default = n
}
```

So we can use `AluOp().default` to get a literal value.

Contributor guide

Open the contributing guide

Research direction

Start with core/src/main/scala/chisel3/ChiselEnum.scala at the linked Type definition around line 236. Read how ChiselEnum and Type are constructed and used, then trace the requested outer-class exposure through nearby callers. Done means the requested extension use case works without runtime casting failure and existing behavior remains compatible.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
embedded-iot
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.