summaryrefslogtreecommitdiff
path: root/chiselFrontend/src/main/scala/chisel3/internal
diff options
context:
space:
mode:
Diffstat (limited to 'chiselFrontend/src/main/scala/chisel3/internal')
-rw-r--r--chiselFrontend/src/main/scala/chisel3/internal/Error.scala95
1 files changed, 61 insertions, 34 deletions
diff --git a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
index 25a3ec2a..6e7e4002 100644
--- a/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
+++ b/chiselFrontend/src/main/scala/chisel3/internal/Error.scala
@@ -2,7 +2,7 @@
package chisel3.internal
-import scala.collection.mutable.ArrayBuffer
+import scala.collection.mutable.{ArrayBuffer, LinkedHashMap}
import chisel3.core._
@@ -15,8 +15,6 @@ private[chisel3] object throwException {
/** Records and reports runtime errors and warnings. */
private[chisel3] class ErrorLog {
- def hasErrors: Boolean = errors.exists(_.isFatal)
-
/** Log an error message */
def error(m: => String): Unit =
errors += new Error(m, getUserLineNumber)
@@ -25,50 +23,83 @@ private[chisel3] class ErrorLog {
def warning(m: => String): Unit =
errors += new Warning(m, getUserLineNumber)
- /** Log a deprecation warning message */
- def deprecated(m: => String): Unit =
- errors += new DeprecationWarning(m, getUserLineNumber)
-
/** Emit an informational message */
def info(m: String): Unit =
println(new Info("[%2.3f] %s".format(elapsedTime/1e3, m), None)) // scalastyle:ignore regex
- /** Prints error messages generated by Chisel at runtime. */
- def report(): Unit = errors foreach println // scalastyle:ignore regex
+ /** Log a deprecation warning message */
+ def deprecated(m: => String): Unit = {
+ val thisEntry = (m, getUserLineNumber)
+ deprecations += ((thisEntry, deprecations.getOrElse(thisEntry, 0) + 1))
+ }
/** Throw an exception if any errors have yet occurred. */
def checkpoint(): Unit = {
- if(hasErrors) {
- import Console._
- throwException(errors.map(_ + "\n").reduce(_ + _) +
- UNDERLINED + "CODE HAS " + errors.filter(_.isFatal).length + RESET +
- UNDERLINED + " " + RED + "ERRORS" + RESET +
- UNDERLINED + " and " + errors.filterNot(_.isFatal).length + RESET +
- UNDERLINED + " " + YELLOW + "WARNINGS" + RESET)
+ val depTag = s"[${Console.BLUE}deprecated${Console.RESET}]"
+ val warnTag = s"[${Console.YELLOW}warn${Console.RESET}]"
+ val errTag = s"[${Console.RED}error${Console.RESET}]"
+ deprecations foreach { case ((message, stackElement), count) =>
+ val line = stackElement match {
+ case Some(stackElement) => s"$depTag ${stackElement.getFileName}:${stackElement.getLineNumber} ($count calls): $message"
+ case None => s"$depTag (unknown location) ($count calls): $message"
+ }
+ println(line)
+ }
+ errors foreach println
+
+ if (!deprecations.isEmpty) {
+ println(s"$warnTag ${Console.YELLOW}There were ${deprecations.size} deprecated function(s) used." +
+ s" These may stop compiling in a future release, you are encouraged to fix these issues.${Console.RESET}")
+ println(s"$warnTag Line numbers for deprecations reported by Chisel may be inaccurate, enable scalac compiler deprecation warnings by either:")
+ println(s"$warnTag In the sbt interactive console, enter:")
+ println(s"""$warnTag set scalacOptions in ThisBuild ++= Seq("-unchecked", "-deprecation")""")
+ println(s"$warnTag or, in your build.sbt, add the line:")
+ println(s"""$warnTag scalacOptions := Seq("-unchecked", "-deprecation")""")
+ }
+
+ val allErrors = errors.filter(_.isFatal)
+ val allWarnings = errors.filter(!_.isFatal)
+
+ if (!allWarnings.isEmpty && !allErrors.isEmpty) {
+ println(s"$errTag There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} and ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ } else if (!allWarnings.isEmpty) {
+ println(s"$warnTag There were ${Console.YELLOW}${allWarnings.size} warning(s)${Console.RESET} during hardware elaboration.")
+ } else if (!allErrors.isEmpty) {
+ println(s"$errTag There were ${Console.RED}${allErrors.size} error(s)${Console.RESET} during hardware elaboration.")
+ }
+
+ if (!allErrors.isEmpty) {
+ throwException("Fatal errors during hardware elaboration")
} else {
- // No fatal errors. Report accumulated warnings and clear them.
- report()
+ // No fatal errors, clear accumulated warnings since they've been reported
errors.clear()
}
}
- private def findFirstUserFrame(stack: Array[StackTraceElement]): Option[StackTraceElement] = {
- def isUserCode(ste: StackTraceElement): Boolean = {
- def isUserModule(c: Class[_]): Boolean =
- c != null && (c == classOf[UserModule] || isUserModule(c.getSuperclass))
- isUserModule(Class.forName(ste.getClassName))
+ /** Returns the best guess at the first stack frame that belongs to user code.
+ */
+ private def getUserLineNumber = {
+ def isChiselClassname(className: String): Boolean = {
+ // List of classpath prefixes that are Chisel internals and should be ignored when looking for user code
+ // utils are not part of internals and errors there can be reported
+ val chiselPrefixes = Set(
+ "java.",
+ "scala.",
+ "chisel3.internal.",
+ "chisel3.core.",
+ "chisel3.package$" // for some compatibility / deprecated types
+ )
+ !chiselPrefixes.filter(className.startsWith(_)).isEmpty
}
- stack.indexWhere(isUserCode) match {
- case x if x < 0 => None
- case x => Some(stack(x))
- }
+ Thread.currentThread().getStackTrace.toList.dropWhile(
+ // Get rid of everything in Chisel core
+ ste => isChiselClassname(ste.getClassName)
+ ).headOption
}
- private def getUserLineNumber =
- findFirstUserFrame(Thread.currentThread().getStackTrace)
-
private val errors = ArrayBuffer[LogEntry]()
+ private val deprecations = LinkedHashMap[(String, Option[StackTraceElement]), Int]()
private val startTime = System.currentTimeMillis
private def elapsedTime: Long = System.currentTimeMillis - startTime
@@ -96,10 +127,6 @@ private class Warning(msg: => String, line: Option[StackTraceElement]) extends L
def format: String = tag("warn", Console.YELLOW)
}
-private class DeprecationWarning(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
- def format: String = tag("warn", Console.CYAN)
-}
-
private class Info(msg: => String, line: Option[StackTraceElement]) extends LogEntry(msg, line) {
def format: String = tag("info", Console.MAGENTA)
}