diff options
| author | Albert Magyar | 2019-12-18 16:21:06 -0500 |
|---|---|---|
| committer | Schuyler Eldridge | 2020-02-19 19:47:17 -0500 |
| commit | 68d9fc84ce510c4ff5eb1907419925d4ea548e04 (patch) | |
| tree | 1c0703f49f09200661820d13d981b34ce548b6aa /src/main/scala/firrtl/options/Phase.scala | |
| parent | 235ec6cbdce6866c8fcd49c0000a7abeeaa4ef80 (diff) | |
Support Singleton Dependencies (#1275)
This makes a change to the Dependency API that breaks chisel3. This
needs to [skip chisel tests], but is fixed with
https://github.com/freechipsproject/chisel3/pull/1270.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@ibm.com>
Diffstat (limited to 'src/main/scala/firrtl/options/Phase.scala')
| -rw-r--r-- | src/main/scala/firrtl/options/Phase.scala | 66 |
1 files changed, 59 insertions, 7 deletions
diff --git a/src/main/scala/firrtl/options/Phase.scala b/src/main/scala/firrtl/options/Phase.scala index e328282f..a9656407 100644 --- a/src/main/scala/firrtl/options/Phase.scala +++ b/src/main/scala/firrtl/options/Phase.scala @@ -8,6 +8,61 @@ import logger.LazyLogging import scala.collection.mutable.LinkedHashSet +import scala.reflect +import scala.reflect.ClassTag + +object Dependency { + def apply[A <: DependencyAPI[_] : ClassTag]: Dependency[A] = { + val clazz = reflect.classTag[A].runtimeClass + Dependency(Left(clazz.asInstanceOf[Class[A]])) + } + + def apply[A <: DependencyAPI[_]](c: Class[_ <: A]): Dependency[A] = { + // It's forbidden to wrap the class of a singleton as a Dependency + require(c.getName.last != '$') + Dependency(Left(c)) + } + + def apply[A <: DependencyAPI[_]](o: A with Singleton): Dependency[A] = Dependency(Right(o)) + + def fromTransform[A <: DependencyAPI[_]](t: A): Dependency[A] = { + if (isSingleton(t)) { + Dependency[A](Right(t.asInstanceOf[A with Singleton])) + } else { + Dependency[A](Left(t.getClass)) + } + } + + private def isSingleton(obj: AnyRef): Boolean = { + reflect.runtime.currentMirror.reflect(obj).symbol.isModuleClass + } +} + +case class Dependency[+A <: DependencyAPI[_]](id: Either[Class[_ <: A], A with Singleton]) { + def getObject(): A = id match { + case Left(c) => safeConstruct(c) + case Right(o) => o + } + + def getSimpleName: String = id match { + case Left(c) => c.getSimpleName + case Right(o) => o.getClass.getSimpleName + } + + def getName: String = id match { + case Left(c) => c.getName + case Right(o) => o.getClass.getName + } + + /** Wrap an [[IllegalAccessException]] due to attempted object construction in a [[DependencyManagerException]] */ + private def safeConstruct[A](a: Class[_ <: A]): A = try { a.newInstance } catch { + case e: IllegalAccessException => throw new DependencyManagerException( + s"Failed to construct '$a'! (Did you try to construct an object?)", e) + case e: InstantiationException => throw new DependencyManagerException( + s"Failed to construct '$a'! (Did you try to construct an inner class or a class with parameters?)", e) + } +} + /** A polymorphic mathematical transform * @tparam A the transformed type */ @@ -42,14 +97,11 @@ trait TransformLike[A] extends LazyLogging { */ trait DependencyAPI[A <: DependencyAPI[A]] { this: TransformLike[_] => - /** The type used to express dependencies: a class which itself has dependencies. */ - type Dependency = Class[_ <: A] - /** All transform that must run before this transform * $seqNote */ - def prerequisites: Seq[Dependency] = Seq.empty - private[options] lazy val _prerequisites: LinkedHashSet[Dependency] = new LinkedHashSet() ++ prerequisites.toSet + def prerequisites: Seq[Dependency[A]] = Seq.empty + private[options] lazy val _prerequisites: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ prerequisites.toSet /** All transforms that must run ''after'' this transform * @@ -70,8 +122,8 @@ trait DependencyAPI[A <: DependencyAPI[A]] { this: TransformLike[_] => * @see [[firrtl.passes.CheckTypes]] for an example of an optional checking [[firrtl.Transform]] * $seqNote */ - def dependents: Seq[Dependency] = Seq.empty - private[options] lazy val _dependents: LinkedHashSet[Dependency] = new LinkedHashSet() ++ dependents.toSet + def dependents: Seq[Dependency[A]] = Seq.empty + private[options] lazy val _dependents: LinkedHashSet[Dependency[A]] = new LinkedHashSet() ++ dependents.toSet /** A function that, given *another* transform (parameter `a`) will return true if this transform invalidates/undos the * effects of the *other* transform (parameter `a`). |
