diff options
| author | Jim Lawson | 2018-02-16 17:10:30 -0800 |
|---|---|---|
| committer | GitHub | 2018-02-16 17:10:30 -0800 |
| commit | edcb81a34dbf8a04d0b011aa1ca07c6e19598f23 (patch) | |
| tree | aba2e3b8b921f9fdc861ed51687735f6d18d7bff | |
| parent | 74a3b302df4422bec47e754cad1703b36ff75cd2 (diff) | |
Replacematcherror - catch exceptions and convert to internal error. (#424)
* Catch exceptions and convert to internal error.
We need to update the displayed message to incorporate a line number and text to be used for the issue.
* Cleanup exception handling/throwing.
Re-throw expected (or uncorrectable exceptions).
Provide Utils.getThrowable() to get the first (eldest) or last throwable in the chain.
Update tests to conform to FreeSpec protocol.
* Minor cleanup
Admit we've updated some deprecated ScalaTest methods.
22 files changed, 199 insertions, 66 deletions
diff --git a/src/main/scala/firrtl/Compiler.scala b/src/main/scala/firrtl/Compiler.scala index 43596765..504ec85c 100644 --- a/src/main/scala/firrtl/Compiler.scala +++ b/src/main/scala/firrtl/Compiler.scala @@ -203,7 +203,7 @@ final case object LowForm extends CircuitForm(0) * this requirement. */ final case object UnknownForm extends CircuitForm(-1) { - override def compare(that: CircuitForm): Int = { error("Illegal to compare UnknownForm"); 0 } + override def compare(that: CircuitForm): Int = { sys.error("Illegal to compare UnknownForm"); 0 } } /** The basic unit of operating on a Firrtl AST */ @@ -331,8 +331,8 @@ object CompilerUtils extends LazyLogging { Seq(new IRToWorkingIR, new ResolveAndCheck, new transforms.DedupModules, new HighFirrtlToMiddleFirrtl) ++ getLoweringTransforms(MidForm, outputForm) case MidForm => Seq(new MiddleFirrtlToLowFirrtl) ++ getLoweringTransforms(LowForm, outputForm) - case LowForm => throwInternalError // should be caught by if above - case UnknownForm => throwInternalError // should be caught by if above + case LowForm => throwInternalError(Some("getLoweringTransforms - LowForm")) // should be caught by if above + case UnknownForm => throwInternalError(Some("getLoweringTransforms - UnknownForm")) // should be caught by if above } } } diff --git a/src/main/scala/firrtl/Driver.scala b/src/main/scala/firrtl/Driver.scala index bc5102d2..99ae6d54 100644 --- a/src/main/scala/firrtl/Driver.scala +++ b/src/main/scala/firrtl/Driver.scala @@ -5,6 +5,7 @@ package firrtl import scala.collection._ import scala.io.Source import scala.sys.process.{BasicIO,stringSeqToProcess} +import scala.util.control.ControlThrowable import java.io.{File, FileNotFoundException} import net.jcazevedo.moultingyaml._ @@ -12,8 +13,9 @@ import logger.Logger import Parser.{IgnoreInfo, InfoMode} import annotations._ import firrtl.annotations.AnnotationYamlProtocol._ +import firrtl.passes.PassException import firrtl.transforms._ -import Utils.throwInternalError +import firrtl.Utils.throwInternalError /** @@ -52,12 +54,23 @@ object Driver { customTransforms: Seq[Transform] = Seq.empty, annotations: AnnotationMap = AnnotationMap(Seq.empty) ): String = { - val parsedInput = Parser.parse(Source.fromFile(input).getLines(), infoMode) val outputBuffer = new java.io.CharArrayWriter - compiler.compile( - CircuitState(parsedInput, ChirrtlForm, Some(annotations)), - outputBuffer, - customTransforms) + try { + val parsedInput = Parser.parse(Source.fromFile(input).getLines(), infoMode) + compiler.compile( + CircuitState(parsedInput, ChirrtlForm, Some(annotations)), + outputBuffer, + customTransforms) + } + + catch { + // Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow) + case p: ControlThrowable => throw p + case p: PassException => throw p + case p: FIRRTLException => throw p + // Treat remaining exceptions as internal errors. + case e: Exception => throwInternalError(exception = Some(e)) + } val outputFile = new java.io.PrintWriter(output) val outputString = outputBuffer.toString @@ -191,19 +204,35 @@ object Driver { } } - val annos = loadAnnotations(optionsManager) + var maybeFinalState: Option[CircuitState] = None + + // Wrap compilation in a try/catch to present Scala MatchErrors in a more user-friendly format. + try { + val annos = loadAnnotations(optionsManager) - val parsedInput = Parser.parse(firrtlSource, firrtlConfig.infoMode) + val parsedInput = Parser.parse(firrtlSource, firrtlConfig.infoMode) - // Does this need to be before calling compiler? - optionsManager.makeTargetDir() + // Does this need to be before calling compiler? + optionsManager.makeTargetDir() + + maybeFinalState = Some(firrtlConfig.compiler.compile( + CircuitState(parsedInput, + ChirrtlForm, + Some(AnnotationMap(annos))), + firrtlConfig.customTransforms + )) + } + + catch { + // Rethrow the exceptions which are expected or due to the runtime environment (out of memory, stack overflow) + case p: ControlThrowable => throw p + case p: PassException => throw p + case p: FIRRTLException => throw p + // Treat remaining exceptions as internal errors. + case e: Exception => throwInternalError(exception = Some(e)) + } - val finalState = firrtlConfig.compiler.compile( - CircuitState(parsedInput, - ChirrtlForm, - Some(AnnotationMap(annos))), - firrtlConfig.customTransforms - ) + val finalState = maybeFinalState.get // Do emission // Note: Single emission target assumption is baked in here @@ -217,7 +246,7 @@ object Driver { emitted.value case OneFilePerModule(dirName) => val emittedModules = finalState.emittedComponents collect { case x: EmittedModule => x } - if (emittedModules.isEmpty) throwInternalError // There should be something + if (emittedModules.isEmpty) throwInternalError() // There should be something emittedModules.foreach { module => val filename = optionsManager.getBuildFileName(firrtlConfig.outputSuffix, s"$dirName/${module.name}") val outputFile = new java.io.PrintWriter(filename) @@ -261,7 +290,7 @@ object Driver { optionsManager.showUsageAsError() failure case result => - throw new Exception(s"Error: Unknown Firrtl Execution result $result") + throwInternalError(Some(s"Error: Unknown Firrtl Execution result $result")) } } else { diff --git a/src/main/scala/firrtl/Emitter.scala b/src/main/scala/firrtl/Emitter.scala index 84b34339..5753fc17 100644 --- a/src/main/scala/firrtl/Emitter.scala +++ b/src/main/scala/firrtl/Emitter.scala @@ -120,7 +120,7 @@ sealed abstract class FirrtlEmitter(form: CircuitForm) extends Transform with Em case WDefInstance(_, _, name, _) => modules += map(name) stmt - case _: WDefInstanceConnector => throwInternalError + case _: WDefInstanceConnector => throwInternalError(Some(s"unrecognized statement: $stmt")) case other => other map onStmt } onStmt(mod.body) @@ -191,7 +191,7 @@ class VerilogEmitter extends SeqTransform with Emitter { case (e: WSubField) => remove_root(e) case (_: WRef) => WRef(ex.name, ex.tpe, InstanceKind, UNKNOWNGENDER) } - case _ => error("Shouldn't be here") + case _ => throwInternalError(Some(s"shouldn't be here: remove_root($ex)")) } /** Turn Params into Verilog Strings */ def stringify(param: Param): String = param match { @@ -205,7 +205,7 @@ class VerilogEmitter extends SeqTransform with Emitter { val wx = bitWidth(tpe) - 1 if (wx > 0) s"[$wx:0]" else "" case ClockType => "" - case _ => error("Trying to write unsupported type in the Verilog Emitter") + case _ => throwInternalError(Some(s"trying to write unsupported type in the Verilog Emitter: $tpe")) } def emit(x: Any)(implicit w: Writer) { emit(x, 0) } def emit(x: Any, top: Int)(implicit w: Writer) { @@ -214,6 +214,7 @@ class VerilogEmitter extends SeqTransform with Emitter { case (t: SIntType) => Seq("$signed(",e,")") case ClockType => e case AnalogType(_) => e + case _ => throwInternalError(Some(s"unrecognized cast: $e")) } x match { case (e: DoPrim) => emit(op_stream(e), top + 1) @@ -240,7 +241,7 @@ class VerilogEmitter extends SeqTransform with Emitter { case (s: Seq[Any]) => s foreach (emit(_, top + 1)) if (top == 0) w write "\n" - case x => println(x); throwInternalError; + case x => throwInternalError(Some(s"trying to emit unsupported operator: $x")) } } @@ -254,6 +255,7 @@ class VerilogEmitter extends SeqTransform with Emitter { case '-' => s"-$width'sh${stringLiteral.tail}" case _ => s"$width'sh${stringLiteral}" }) + case _ => throwInternalError(Some(s"attempt to print unrecognized expression: $e")) } def op_stream(doprim: DoPrim): Seq[Any] = { @@ -266,16 +268,19 @@ class VerilogEmitter extends SeqTransform with Emitter { case Some(_) => e.tpe match { case (_: SIntType) => Seq("$signed(", e, ")") case (_: UIntType) => Seq("$signed({1'b0,", e, "})") + case _ => throwInternalError(Some(s"unrecognized type: $e")) } } } def cast(e: Expression): Any = doprim.tpe match { case (t: UIntType) => e case (t: SIntType) => Seq("$signed(",e,")") + case _ => throwInternalError(Some(s"cast - unrecognized type: $e")) } def cast_as(e: Expression): Any = e.tpe match { case (t: UIntType) => e case (t: SIntType) => Seq("$signed(",e,")") + case _ => throwInternalError(Some(s"cast_as - unrecognized type: $e")) } def a0: Expression = doprim.args.head def a1: Expression = doprim.args(1) diff --git a/src/main/scala/firrtl/Utils.scala b/src/main/scala/firrtl/Utils.scala index 76f58f30..e5a7e6be 100644 --- a/src/main/scala/firrtl/Utils.scala +++ b/src/main/scala/firrtl/Utils.scala @@ -12,6 +12,20 @@ import scala.collection.mutable.{StringBuilder, ArrayBuffer, LinkedHashMap, Hash import java.io.PrintWriter import logger.LazyLogging +object FIRRTLException { + def defaultMessage(message: String, cause: Throwable) = { + if (message != null) { + message + } else if (cause != null) { + cause.toString + } else { + null + } + } +} +class FIRRTLException(val str: String, cause: Throwable = null) + extends RuntimeException(FIRRTLException.defaultMessage(str, cause), cause) + object seqCat { def apply(args: Seq[Expression]): Expression = args.length match { case 0 => Utils.error("Empty Seq passed to seqcat") @@ -29,7 +43,7 @@ object seqCat { object toBits { def apply(e: Expression): Expression = e match { case ex @ (_: WRef | _: WSubField | _: WSubIndex) => hiercat(ex) - case t => Utils.error("Invalid operand expression for toBits!") + case t => Utils.error(s"Invalid operand expression for toBits: $e") } private def hiercat(e: Expression): Expression = e.tpe match { case t: VectorType => seqCat((0 until t.size).reverse map (i => @@ -37,14 +51,14 @@ object toBits { case t: BundleType => seqCat(t.fields map (f => hiercat(WSubField(e, f.name, f.tpe, UNKNOWNGENDER)))) case t: GroundType => DoPrim(AsUInt, Seq(e), Seq.empty, UnknownType) - case t => Utils.error("Unknown type encountered in toBits!") + case t => Utils.error(s"Unknown type encountered in toBits: $e") } } object getWidth { def apply(t: Type): Width = t match { case t: GroundType => t.width - case _ => Utils.error("No width!") + case _ => Utils.error(s"No width: $t") } def apply(e: Expression): Width = apply(e.tpe) } @@ -55,7 +69,7 @@ object bitWidth { case t: VectorType => t.size * bitWidth(t.tpe) case t: BundleType => t.fields.map(f => bitWidth(f.tpe)).foldLeft(BigInt(0))(_+_) case GroundType(IntWidth(width)) => width - case t => Utils.error("Unknown type encountered in bitWidth!") + case t => Utils.error(s"Unknown type encountered in bitWidth: $dt") } } @@ -112,7 +126,7 @@ object fromBits { (tmpOffset, stmts ++ substmts) } case t: GroundType => getPartGround(lhs, t, rhs, offset) - case t => Utils.error("Unknown type encountered in fromBits!") + case t => Utils.error(s"Unknown type encountered in fromBits: $lhst") } } @@ -125,11 +139,46 @@ object flattenType { def apply(t: Type) = UIntType(IntWidth(bitWidth(t))) } -class FIRRTLException(val str: String) extends Exception(str) - object Utils extends LazyLogging { - def throwInternalError = - error("Internal Error! Please file an issue at https://github.com/ucb-bar/firrtl/issues") + /** Unwind the causal chain until we hit the initial exception (which may be the first). + * + * @param maybeException - possible exception triggering the error, + * @param first - true if we want the first (eldest) exception in the chain, + * @return first or last Throwable in the chain. + */ + def getThrowable(maybeException: Option[Throwable], first: Boolean): Throwable = { + maybeException match { + case Some(e: Throwable) => { + val t = e.getCause + if (t != null) { + if (first) { + getThrowable(Some(t), first) + } else { + t + } + } else { + e + } + } + case None | null => null + } + } + + /** Throw an internal error, possibly due to an exception. + * + * @param message - possible string to emit, + * @param exception - possible exception triggering the error. + */ + def throwInternalError(message: Option[String] = None, exception: Option[Exception] = None) = { + // We'll get the first exception in the chain, keeping it intact. + val first = true + val throwable = getThrowable(exception, true) + val string: String = message match { + case Some(s: String) => s + "\n" + case _ => "" + } + error("Internal Error! %sPlease file an issue at https://github.com/ucb-bar/firrtl/issues".format(string), throwable) + } private[firrtl] def time[R](block: => R): (Double, R) = { val t0 = System.nanoTime() @@ -210,7 +259,7 @@ object Utils extends LazyLogging { } } def get_flip(t: Type, i: Int, f: Orientation): Orientation = { - if (i >= get_size(t)) error("Shouldn't be here") + if (i >= get_size(t)) throwInternalError(Some(s"get_flip: shouldn't be here - $i >= get_size($t)")) t match { case (_: GroundType) => f case (tx: BundleType) => @@ -386,7 +435,7 @@ object Utils extends LazyLogging { //>>>>>>> e54fb610c6bf0a7fe5c9c0f0e0b3acbb3728cfd0 // ================================= - def error(str: String) = throw new FIRRTLException(str) + def error(str: String, cause: Throwable = null) = throw new FIRRTLException(str, cause) //// =============== EXPANSION FUNCTIONS ================ def get_size(t: Type): Int = t match { @@ -426,7 +475,7 @@ object Utils extends LazyLogging { ilen + get_size(t1x.tpe), jlen + get_size(t2x.tpe)) }._1 case (ClockType, ClockType) => if (flip1 == flip2) Seq((0, 0)) else Nil - case _ => Utils.error("shouldn't be here") + case _ => throwInternalError(Some(s"get_valid_points: shouldn't be here - ($t1, $t2)")) } } @@ -472,9 +521,9 @@ object Utils extends LazyLogging { def get_field(v: Type, s: String): Field = v match { case vx: BundleType => vx.fields find (_.name == s) match { case Some(ft) => ft - case None => Utils.error("Shouldn't be here") + case None => throwInternalError(Some(s"get_field: shouldn't be here - $v.$s")) } - case vx => Utils.error("Shouldn't be here") + case vx => throwInternalError(Some(s"get_field: shouldn't be here - $v")) } def times(flip: Orientation, d: Direction): Direction = times(flip, d) @@ -517,7 +566,7 @@ object Utils extends LazyLogging { case ex: Mux => MALE case ex: ValidIf => MALE case WInvalid => MALE - case ex => println(ex); error("Shouldn't be here") + case ex => throwInternalError(Some(s"gender: shouldn't be here - $e")) } def get_gender(s: Statement): Gender = s match { case sx: DefWire => BIGENDER diff --git a/src/main/scala/firrtl/Visitor.scala b/src/main/scala/firrtl/Visitor.scala index c5a21b23..d0173774 100644 --- a/src/main/scala/firrtl/Visitor.scala +++ b/src/main/scala/firrtl/Visitor.scala @@ -11,6 +11,7 @@ import PrimOps._ import FIRRTLParser._ import Parser.{AppendInfo, GenInfo, IgnoreInfo, InfoMode, UseInfo} import firrtl.ir._ +import Utils.throwInternalError class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] { @@ -92,7 +93,7 @@ class Visitor(infoMode: InfoMode) extends FIRRTLBaseVisitor[FirrtlNode] { case (null, str, null, null) => StringParam(name, visitStringLit(str)) case (null, null, dbl, null) => DoubleParam(name, dbl.getText.toDouble) case (null, null, null, raw) => RawStringParam(name, raw.getText.tail.init) // Remove "\'"s - case _ => throw new Exception(s"Internal error: Visiting impossible parameter ${ctx.getText}") + case _ => throwInternalError(Some(s"visiting impossible parameter ${ctx.getText}")) } } diff --git a/src/main/scala/firrtl/annotations/AnnotationUtils.scala b/src/main/scala/firrtl/annotations/AnnotationUtils.scala index ab580e88..240c46d6 100644 --- a/src/main/scala/firrtl/annotations/AnnotationUtils.scala +++ b/src/main/scala/firrtl/annotations/AnnotationUtils.scala @@ -56,7 +56,7 @@ object AnnotationUtils { val DecPattern = """([1-9]\d*)""".r def findClose(tokens: Seq[String], index: Int, nOpen: Int): Seq[String] = { if(index >= tokens.size) { - error("Cannot find closing bracket ]") + Utils.error("Cannot find closing bracket ]") } else tokens(index) match { case "[" => findClose(tokens, index + 1, nOpen + 1) case "]" if nOpen == 1 => tokens.slice(1, index) @@ -81,6 +81,8 @@ object AnnotationUtils { } if(validComponentName(s)) { parse(tokenize(s)) - } else error(s"Cannot convert $s into an expression.") + } else { + Utils.error(s"Cannot convert $s into an expression.") + } } } diff --git a/src/main/scala/firrtl/passes/CheckWidths.scala b/src/main/scala/firrtl/passes/CheckWidths.scala index 8f6ab18f..55391d99 100644 --- a/src/main/scala/firrtl/passes/CheckWidths.scala +++ b/src/main/scala/firrtl/passes/CheckWidths.scala @@ -50,7 +50,7 @@ object CheckWidths extends Pass { def hasWidth(tpe: Type): Boolean = tpe match { case GroundType(IntWidth(w)) => true case GroundType(_) => false - case _ => println(tpe); throwInternalError + case _ => throwInternalError(Some(s"hasWidth - $tpe")) } def check_width_t(info: Info, mname: String)(t: Type): Type = diff --git a/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala b/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala index 05604bd8..b52dacb7 100644 --- a/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala +++ b/src/main/scala/firrtl/passes/ConvertFixedToSInt.scala @@ -7,7 +7,7 @@ import firrtl.PrimOps._ import firrtl.ir._ import firrtl._ import firrtl.Mappers._ -import firrtl.Utils.{sub_type, module_type, field_type, max, error} +import firrtl.Utils.{sub_type, module_type, field_type, max, error, throwInternalError} /** Replaces FixedType with SIntType, and correctly aligns all binary points */ @@ -19,7 +19,7 @@ object ConvertFixedToSInt extends Pass { } else if (point - p < 0) { DoPrim(Shr, Seq(e), Seq(p - point), UnknownType) } else e - case FixedType(w, p) => error("Shouldn't be here") + case FixedType(w, p) => throwInternalError(Some(s"alignArg: shouldn't be here - $e")) case _ => e } def calcPoint(es: Seq[Expression]): BigInt = @@ -29,7 +29,7 @@ object ConvertFixedToSInt extends Pass { }).reduce(max(_, _)) def toSIntType(t: Type): Type = t match { case FixedType(IntWidth(w), IntWidth(p)) => SIntType(IntWidth(w)) - case FixedType(w, p) => error("Shouldn't be here") + case FixedType(w, p) => throwInternalError(Some(s"toSIntType: shouldn't be here - $t")) case _ => t map toSIntType } def run(c: Circuit): Circuit = { diff --git a/src/main/scala/firrtl/passes/ExpandWhens.scala b/src/main/scala/firrtl/passes/ExpandWhens.scala index 959e824a..519a1e1a 100644 --- a/src/main/scala/firrtl/passes/ExpandWhens.scala +++ b/src/main/scala/firrtl/passes/ExpandWhens.scala @@ -169,7 +169,7 @@ object ExpandWhens extends Pass { } Block(Seq(conseqStmt, altStmt) ++ memos) case block: Block => block map expandWhens(netlist, defaults, p) - case _ => throwInternalError + case _ => throwInternalError() } val netlist = new Netlist // Add ports to netlist diff --git a/src/main/scala/firrtl/passes/InferWidths.scala b/src/main/scala/firrtl/passes/InferWidths.scala index 11b819ce..aacd3656 100644 --- a/src/main/scala/firrtl/passes/InferWidths.scala +++ b/src/main/scala/firrtl/passes/InferWidths.scala @@ -333,7 +333,7 @@ object InferWidths extends Pass { case wx: MinusWidth => map2(solve(wx.arg1), solve(wx.arg2), {_ - _}) case wx: ExpWidth => map2(Some(BigInt(2)), solve(wx.arg1), pow_minus_one) case wx: IntWidth => Some(wx.width) - case wx => println(wx); error("Shouldn't be here"); None; + case wx => throwInternalError(Some(s"solve: shouldn't be here - %$wx")); None; } solve(w) match { diff --git a/src/main/scala/firrtl/passes/RemoveAccesses.scala b/src/main/scala/firrtl/passes/RemoveAccesses.scala index 37b92a9e..9b19b221 100644 --- a/src/main/scala/firrtl/passes/RemoveAccesses.scala +++ b/src/main/scala/firrtl/passes/RemoveAccesses.scala @@ -95,7 +95,7 @@ object RemoveAccesses extends Pass { case (_:WSubAccess| _: WSubField| _: WSubIndex| _: WRef) if hasAccess(e) => val rs = getLocations(e) rs find (x => x.guard != one) match { - case None => error("Shouldn't be here") + case None => throwInternalError(Some(s"removeMale: shouldn't be here - $e")) case Some(_) => val (wire, temp) = create_temp(e) val temps = create_exps(temp) diff --git a/src/main/scala/firrtl/passes/RemoveValidIf.scala b/src/main/scala/firrtl/passes/RemoveValidIf.scala index 68d16c30..7d714be7 100644 --- a/src/main/scala/firrtl/passes/RemoveValidIf.scala +++ b/src/main/scala/firrtl/passes/RemoveValidIf.scala @@ -24,7 +24,7 @@ object RemoveValidIf extends Pass { case _: UIntType => UIntZero case _: SIntType => SIntZero case ClockType => ClockZero - case other => throwInternalError + case other => throwInternalError() } // Recursive. Replaces IsInvalid with connecting zero diff --git a/src/main/scala/firrtl/passes/Resolves.scala b/src/main/scala/firrtl/passes/Resolves.scala index c8ba43bf..b601c81e 100644 --- a/src/main/scala/firrtl/passes/Resolves.scala +++ b/src/main/scala/firrtl/passes/Resolves.scala @@ -5,6 +5,7 @@ package firrtl.passes import firrtl._ import firrtl.ir._ import firrtl.Mappers._ +import Utils.throwInternalError object ResolveKinds extends Pass { type KindMap = collection.mutable.LinkedHashMap[String, Kind] @@ -84,19 +85,19 @@ object CInferMDir extends Pass { mports get e.name match { case None => case Some(p) => mports(e.name) = (p, dir) match { - case (MInfer, MInfer) => Utils.error("Shouldn't be here") + case (MInfer, MInfer) => throwInternalError(Some(s"infer_mdir_e: shouldn't be here - $p, $dir")) case (MInfer, MWrite) => MWrite case (MInfer, MRead) => MRead case (MInfer, MReadWrite) => MReadWrite - case (MWrite, MInfer) => Utils.error("Shouldn't be here") + case (MWrite, MInfer) => throwInternalError(Some(s"infer_mdir_e: shouldn't be here - $p, $dir")) case (MWrite, MWrite) => MWrite case (MWrite, MRead) => MReadWrite case (MWrite, MReadWrite) => MReadWrite - case (MRead, MInfer) => Utils.error("Shouldn't be here") + case (MRead, MInfer) => throwInternalError(Some(s"infer_mdir_e: shouldn't be here - $p, $dir")) case (MRead, MWrite) => MReadWrite case (MRead, MRead) => MRead case (MRead, MReadWrite) => MReadWrite - case (MReadWrite, MInfer) => Utils.error("Shouldn't be here") + case (MReadWrite, MInfer) => throwInternalError(Some(s"infer_mdir_e: shouldn't be here - $p, $dir")) case (MReadWrite, MWrite) => MReadWrite case (MReadWrite, MRead) => MReadWrite case (MReadWrite, MReadWrite) => MReadWrite diff --git a/src/main/scala/firrtl/passes/Uniquify.scala b/src/main/scala/firrtl/passes/Uniquify.scala index 54b94939..661dbf4e 100644 --- a/src/main/scala/firrtl/passes/Uniquify.scala +++ b/src/main/scala/firrtl/passes/Uniquify.scala @@ -109,7 +109,7 @@ object Uniquify extends Transform { } recUniquifyNames(t, namespace) match { case tx: BundleType => tx - case tx => error("Shouldn't be here") + case tx => throwInternalError(Some(s"uniquifyNames: shouldn't be here - $tx")) } } diff --git a/src/main/scala/firrtl/passes/clocklist/ClockList.scala b/src/main/scala/firrtl/passes/clocklist/ClockList.scala index 073eb050..be4d99fc 100644 --- a/src/main/scala/firrtl/passes/clocklist/ClockList.scala +++ b/src/main/scala/firrtl/passes/clocklist/ClockList.scala @@ -44,7 +44,7 @@ class ClockList(top: String, writer: Writer) extends Pass { val modulesToInline = (c.modules.collect { case Module(_, n, _, _) if n != top => ModuleName(n, CircuitName(c.main)) }).toSet val inlineTransform = new InlineInstances val inlinedCircuit = inlineTransform.run(onlyClockCircuit, modulesToInline, Set(), None).circuit - val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError) + val topModule = inlinedCircuit.modules.find(_.name == top).getOrElse(throwInternalError(Some("no top module"))) // Build a hashmap of connections to use for getOrigins val connects = getConnects(topModule) diff --git a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala index b18ed289..bf0612ac 100644 --- a/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala +++ b/src/main/scala/firrtl/passes/memlib/ReplaceMemMacros.scala @@ -224,7 +224,7 @@ class ReplaceMemMacros(writer: ConfWriter) extends Transform { val pins = getMyAnnotations(state) match { case Nil => Nil case Seq(PinAnnotation(CircuitName(c), pins)) => pins - case _ => throwInternalError + case _ => throwInternalError(Some(s"execute: getMyAnnotations - ${getMyAnnotations(state)}")) } val annos = (pins.foldLeft(Seq[Annotation]()) { (seq, pin) => seq ++ memMods.collect { diff --git a/src/main/scala/firrtl/passes/memlib/YamlUtils.scala b/src/main/scala/firrtl/passes/memlib/YamlUtils.scala index 4cc28e42..3e0c6a44 100644 --- a/src/main/scala/firrtl/passes/memlib/YamlUtils.scala +++ b/src/main/scala/firrtl/passes/memlib/YamlUtils.scala @@ -31,7 +31,7 @@ class YamlFileReader(file: String) { catch { case e: Exception => None } ) } - else error("Yaml file doesn't exist!") + else sys.error("Yaml file doesn't exist!") } } diff --git a/src/main/scala/firrtl/transforms/CheckCombLoops.scala b/src/main/scala/firrtl/transforms/CheckCombLoops.scala index bb2ffea9..98d6c3d1 100644 --- a/src/main/scala/firrtl/transforms/CheckCombLoops.scala +++ b/src/main/scala/firrtl/transforms/CheckCombLoops.scala @@ -71,9 +71,9 @@ class CheckCombLoops extends Transform { memport.expr match { case memref: WRef => LogicNode(s.name,Some(memref.name),Some(memport.name)) - case _ => throwInternalError + case _ => throwInternalError(Some(s"toLogicNode: unrecognized subsubfield expression - $memport")) } - case _ => throwInternalError + case _ => throwInternalError(Some(s"toLogicNode: unrecognized subfield expression - $s")) } } diff --git a/src/main/scala/firrtl/transforms/ConstantPropagation.scala b/src/main/scala/firrtl/transforms/ConstantPropagation.scala index d08a7e6b..086f1cee 100644 --- a/src/main/scala/firrtl/transforms/ConstantPropagation.scala +++ b/src/main/scala/firrtl/transforms/ConstantPropagation.scala @@ -320,7 +320,7 @@ class ConstantPropagation extends Transform { case node: DefNode => node.copy(name = newName) case wire: DefWire => wire.copy(name = newName) case reg: DefRegister => reg.copy(name = newName) - case other => throwInternalError + case other => throwInternalError() } case other => other map backPropStmt } diff --git a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala index 22e7da6e..054705c0 100644 --- a/src/main/scala/firrtl/transforms/DeadCodeElimination.scala +++ b/src/main/scala/firrtl/transforms/DeadCodeElimination.scala @@ -63,7 +63,7 @@ class DeadCodeElimination extends Transform { case ref @ (_: WRef | _: WSubField) => refs += ref case nested @ (_: Mux | _: DoPrim | _: ValidIf) => nested map rec case ignore @ (_: Literal) => // Do nothing - case unexpected => throwInternalError + case unexpected => throwInternalError() } e } @@ -136,7 +136,7 @@ class DeadCodeElimination extends Transform { // Add all ports as vertices mod.ports.foreach { case Port(_, name, _, _: GroundType) => depGraph.addVertex(LogicNode(mod.name, name)) - case other => throwInternalError + case other => throwInternalError() } onStmt(mod.body) } @@ -261,7 +261,7 @@ class DeadCodeElimination extends Transform { None } else { - if (ext.ports != portsx) throwInternalError // Sanity check + if (ext.ports != portsx) throwInternalError() // Sanity check Some(ext.copy(ports = portsx)) } } diff --git a/src/main/scala/firrtl/transforms/RemoveWires.scala b/src/main/scala/firrtl/transforms/RemoveWires.scala index a1fb32db..931288d9 100644 --- a/src/main/scala/firrtl/transforms/RemoveWires.scala +++ b/src/main/scala/firrtl/transforms/RemoveWires.scala @@ -99,7 +99,7 @@ class RemoveWires extends Transform { otherStmts += other case EmptyStmt => // Dont bother keeping EmptyStmts around case block: Block => block map onStmt - case _ => throwInternalError + case _ => throwInternalError() } stmt } diff --git a/src/test/scala/firrtlTests/InternalErrorSpec.scala b/src/test/scala/firrtlTests/InternalErrorSpec.scala new file mode 100644 index 00000000..85c9c67d --- /dev/null +++ b/src/test/scala/firrtlTests/InternalErrorSpec.scala @@ -0,0 +1,46 @@ +// See LICENSE for license details. + +package firrtlTests + +import java.io.File + +import firrtl._ +import firrtl.Utils.getThrowable +import firrtl.util.BackendCompilationUtilities +import org.scalatest.{FreeSpec, Matchers} + + +class InternalErrorSpec extends FreeSpec with Matchers with BackendCompilationUtilities { + "Unexpected exceptions" - { + val input = + """ + |circuit Dummy : + | module Dummy : + | input clock : Clock + | input x : UInt<1> + | output y : UInt<1> + | output io : { flip in : UInt<16>, out : UInt<16> } + | y <= shr(x, UInt(1)); this should generate an exception in PrimOps.scala:127. + | """.stripMargin + + var exception: Exception = null + "should throw a FIRRTLException" in { + val manager = new ExecutionOptionsManager("test") with HasFirrtlOptions { + commonOptions = CommonOptions(topName = "Dummy") + firrtlOptions = FirrtlExecutionOptions(firrtlSource = Some(input), compilerName = "low") + } + exception = intercept[FIRRTLException] { + firrtl.Driver.execute(manager) + } + } + + "should contain the expected string" in { + assert(exception.getMessage.contains("Internal Error! Please file an issue")) + } + + "should contain the name of the file originating the exception in the stack trace" in { + val first = true + assert(getThrowable(Some(exception), first).getStackTrace exists (_.getFileName.contains("PrimOps.scala"))) + } + } +} |
