aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/reporting/ErrorMessages.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/dotty/tools/dotc/reporting/ErrorMessages.scala')
-rw-r--r--src/dotty/tools/dotc/reporting/ErrorMessages.scala117
1 files changed, 117 insertions, 0 deletions
diff --git a/src/dotty/tools/dotc/reporting/ErrorMessages.scala b/src/dotty/tools/dotc/reporting/ErrorMessages.scala
new file mode 100644
index 000000000..7186ccbe2
--- /dev/null
+++ b/src/dotty/tools/dotc/reporting/ErrorMessages.scala
@@ -0,0 +1,117 @@
+package dotty.tools
+package dotc
+package reporting
+
+import dotc.core._
+import Contexts.Context, Decorators._, Symbols._
+import dotc.printing.SyntaxHighlighting._
+import util.{SourcePosition, NoSourcePosition}
+
+object ErrorMessages {
+ import dotc.ast.Trees._
+ import dotc.ast.untpd
+
+ implicit class ShouldExplainCtx(val c: Context) extends AnyVal {
+ def shouldExplain(expl: ErrorMessage): Boolean = {
+ implicit val ctx = c
+ expl match {
+ case _: NoExplanation => false
+ case expl if ctx.settings.explainerrors.value => true
+ case _ => false
+ }
+ }
+ }
+
+ trait ErrorMessage {
+ def kind: String
+ def msg: String
+ def explanation: String
+ }
+
+ case class NoExplanation(msg: String)(implicit val kind: String) extends ErrorMessage {
+ val explanation = ""
+ }
+
+ object Syntax {
+ implicit val kind: String = "Syntax"
+ implicit def stringToErrorMessage(s: String): ErrorMessage = NoExplanation(s)
+
+ abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context, val kind: String) extends ErrorMessage {
+ val explanation = {
+ val tryString = tryBody match {
+ case Block(Nil, untpd.EmptyTree) => "{}"
+ case _ => tryBody.show
+ }
+
+ val code1 =
+ s"""|try $tryString catch {
+ | case t: Throwable => ???
+ |}""".stripMargin
+
+ val code2 =
+ s"""|try $tryString finally {
+ | // perform your cleanup here!
+ |}""".stripMargin
+
+ hl"""|Explanation:
+ |============
+ |A ${"try"} expression should be followed by some mechanism to handle any exceptions
+ |thrown. Typically a ${"catch"} expression follows the ${"try"} and pattern matches
+ |on any expected exceptions. For example:
+ |
+ |$code1
+ |
+ |It is also possible to follow a ${"try"} immediately by a ${"finally"} - letting the
+ |exception propagate - but still allowing for some clean up in ${"finally"}:
+ |
+ |$code2
+ """.stripMargin
+ }
+ }
+
+ case class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context, override val kind: String)
+ extends EmptyCatchOrFinallyBlock(tryBody) {
+ val msg =
+ hl"""The ${"catch"} block does not contain a valid expression, try adding a case like - `${"case e: Exception =>"}` to the block"""
+ }
+
+ case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context, override val kind: String)
+ extends EmptyCatchOrFinallyBlock(tryBody) {
+ val msg =
+ hl"""A ${"try"} without ${"catch"} or ${"finally"} is equivalent to putting its body in a block; no exceptions are handled."""
+ }
+ }
+
+ object Type {
+ implicit val kind: String = "Type"
+ implicit def stringToErrorMessage(s: String): ErrorMessage = NoExplanation(s)
+
+ case class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context, val kind: String) extends ErrorMessage {
+ val msg =
+ em"duplicate pattern variable: `${bind.name}`"
+
+ val explanation = {
+ val pat = tree.pat.show
+ val guard = tree.guard match {
+ case untpd.EmptyTree => ""
+ case guard => s"if ${guard.show}"
+ }
+
+ val body = tree.body match {
+ case Block(Nil, untpd.EmptyTree) => ""
+ case body => s" ${body.show}"
+ }
+
+ val caseDef = s"case $pat$guard => $body"
+
+ hl"""|Explanation
+ |===========
+ |For each ${"case"} bound variable names have to be unique. In:
+ |
+ |$caseDef
+ |
+ |`${bind.name}` is not unique. Rename one of the binds!""".stripMargin
+ }
+ }
+ }
+}