chipsalliance / chipsalliance/chisel
[Feature Request] expose outer class of `ChiselEnum#Type`
- 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
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