summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala31
-rw-r--r--src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala41
2 files changed, 70 insertions, 2 deletions
diff --git a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
index 8dbc5a54..d1ccfb1b 100644
--- a/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
+++ b/core/src/main/scala/chisel3/experimental/hierarchy/Hierarchy.scala
@@ -4,7 +4,7 @@ package chisel3.experimental.hierarchy
import chisel3._
import scala.collection.mutable.{HashMap, HashSet}
-import scala.reflect.runtime.universe.WeakTypeTag
+import scala.reflect.runtime.universe.TypeTag
import chisel3.internal.BaseModule.IsClone
import chisel3.experimental.BaseModule
import _root_.firrtl.annotations.IsModule
@@ -25,12 +25,39 @@ sealed trait Hierarchy[+A] {
private[chisel3] val cache = HashMap[Data, Data]()
private[chisel3] def getInnerDataContext: Option[BaseModule]
+ /** Determine whether underlying proto is of type provided.
+ *
+ * @note IMPORTANT: this function requires summoning a TypeTag[B], which will fail if B is an inner class.
+ * @note IMPORTANT: this function IGNORES type parameters, akin to normal type erasure.
+ * @note IMPORTANT: this function relies on Java reflection for underlying proto, but Scala reflection for provided type
+ *
+ * E.g. isA[List[Int]] will return true, even if underlying proto is of type List[String]
+ * @return Whether underlying proto is of provided type (with caveats outlined above)
+ */
+ def isA[B : TypeTag]: Boolean = {
+ val tptag = implicitly[TypeTag[B]]
+ val name = tptag.tpe.toString
+ inBaseClasses(name)
+ }
+
+ private lazy val superClasses = calculateSuperClasses(proto.getClass())
+ private def calculateSuperClasses(clz: Class[_]): Set[String] = {
+ if(clz != null) {
+ Set(clz.getCanonicalName()) ++
+ clz.getInterfaces().flatMap(i => calculateSuperClasses(i)) ++
+ calculateSuperClasses(clz.getSuperclass())
+ } else {
+ Set.empty[String]
+ }
+ }
+ private def inBaseClasses(clz: String): Boolean = superClasses.contains(clz)
+
/** Used by Chisel's internal macros. DO NOT USE in your normal Chisel code!!!
* Instead, mark the field you are accessing with [[@public]]
*
* Given a selector function (that) which selects a member from the original, return the
- * corresponding member from the hierarhcy.
+ * corresponding member from the hierarchy.
*
* Our @instantiable and @public macros generate the calls to this apply method
*
diff --git a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
index 6c227866..0795e76c 100644
--- a/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
+++ b/src/test/scala/chiselTests/experimental/hierarchy/InstanceSpec.scala
@@ -714,5 +714,46 @@ class InstanceSpec extends ChiselFunSpec with Utils {
}
}
}
+ describe("9: isA[..]") {
+ it("9.0: it should work on simple classes") {
+ class Top extends Module {
+ val d = Definition(new AddOne)
+ require(d.isA[AddOne])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.1: it should not work on inner classes") {
+ class InnerClass extends Module
+ class Top extends Module {
+ val d = Definition(new InnerClass)
+ "require(d.isA[Module])" should compile // ensures that the test below is checking something useful
+ "require(d.isA[InnerClass])" shouldNot compile
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.2: it should work on super classes") {
+ class InnerClass extends Module
+ class Top extends Module {
+ val d = Definition(new InnerClass)
+ require(d.isA[Module])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ it("9.2: it should work after casts") {
+ class Top extends Module {
+ val d0: Definition[Module] = Definition(new AddOne)
+ require(d0.isA[AddOne])
+ val d1: Definition[Module] = Definition((new AddOne).asInstanceOf[Module])
+ require(d1.isA[AddOne])
+ val i0: Instance[Module] = Instance(d0)
+ require(i0.isA[AddOne])
+ val i1: Instance[Module] = Instance(d1)
+ require(i1.isA[AddOne])
+ val i2: Instance[Module] = Instance(Definition(new AddOne))
+ require(i2.isA[AddOne])
+ }
+ getFirrtlAndAnnos(new Top)
+ }
+ }
}