Skip to content

Commit c9a202f

Browse files
committed
Add links to Awsome Error Messages
Infrastructure to check URL exisitence in tests to keep links alive. Link checking is switched off automatically in case github.com can't be reached. It can be switched off via a system property as well.
1 parent 123eb4e commit c9a202f

File tree

5 files changed

+244
-93
lines changed

5 files changed

+244
-93
lines changed

compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,17 @@ sealed trait DocumentationLink {
2222
def url: String
2323
}
2424

25+
/** A documentation link can be rendered by tooling to direct the programmer to
26+
* good resources for more details related to the compiler error or warning.
27+
*
28+
* To keep base links at a single place use the cases classes to share a common
29+
* prefix.
30+
*
31+
* Links are checked for existence in tests in `dotty.tools.dotc.reporting.ErrorMessagesTests`
32+
* if the error class is tested there.
33+
*/
2534
object DocumentationLink {
26-
case class LanguageSpec(text: String = "Language Specification", suffix: String) extends DocumentationLink {
35+
case class LanguageSpec(text: String = "Scala Language Specification", suffix: String) extends DocumentationLink {
2736
val url = s"https://www.scala-lang.org/files/archive/spec/2.13/$suffix"
2837
}
2938
case class TourUrl(text: String, suffix: String) extends DocumentationLink {

compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import dotty.tools.dotc.ast.Trees
2323
import dotty.tools.dotc.ast.untpd.Modifiers
2424
import dotty.tools.dotc.core.Flags.{FlagSet, Mutable}
2525
import dotty.tools.dotc.core.SymDenotations.SymDenotation
26-
import dotty.tools.dotc.reporting.diagnostic.DocumentationLink.{DottyDocs, LanguageSpec}
26+
import diagnostic.DocumentationLink.{DottyDocs, LanguageSpec, TourUrl}
2727

2828
import scala.util.control.NonFatal
2929

@@ -99,10 +99,13 @@ object messages {
9999
import ast.tpd
100100

101101
/** Helper methods for messages */
102-
def implicitClassRestrictionsText(implicit ctx: Context) =
103-
hl"""|${NoColor("For a full list of restrictions on implicit classes visit")}
104-
|${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}"""
102+
private def tryExpressionLinks = List(
103+
LanguageSpec(suffix = "06-expressions.html#try-expressions")
104+
)
105105

106+
private def implicitClassLinks = List(
107+
TourUrl("More information on implicit classes", "core/implicit-classes.html")
108+
)
106109

107110
// Syntax Errors ---------------------------------------------------------- //
108111
abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context)
@@ -140,17 +143,17 @@ object messages {
140143
|correctly handles transfer functions like ${"return"}."""
141144
}
142145

143-
override def links: List[DocumentationLink] = List(
144-
LanguageSpec(suffix = "06-expressions.html#try-expressions")
145-
)
146+
override def links = tryExpressionLinks
146147
}
147148

148149
case class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context)
149-
extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) {
150+
extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) {
150151
val kind = "Syntax"
151152
val msg =
152153
hl"""|The ${"catch"} block does not contain a valid expression, try
153154
|adding a case like - `${"case e: Exception =>"}` to the block"""
155+
156+
override def links = tryExpressionLinks
154157
}
155158

156159
case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context)
@@ -159,6 +162,8 @@ object messages {
159162
val msg =
160163
hl"""|A ${"try"} without ${"catch"} or ${"finally"} is equivalent to putting
161164
|its body in a block; no exceptions are handled."""
165+
166+
override def links = tryExpressionLinks
162167
}
163168

164169
case class DeprecatedWithOperator()(implicit ctx: Context)
@@ -453,8 +458,6 @@ object messages {
453458
|the same name created by the compiler which would cause a naming conflict if it
454459
|were allowed.
455460
|
456-
|""" + implicitClassRestrictionsText + hl"""|
457-
|
458461
|To resolve the conflict declare ${cdef.name} inside of an ${"object"} then import the class
459462
|from the object at the use site if needed, for example:
460463
|
@@ -463,8 +466,10 @@ object messages {
463466
|}
464467
|
465468
|// At the use site:
466-
|import Implicits.${cdef.name}"""
469+
|${"import Implicits"}.${cdef.name}"""
467470
}
471+
472+
override def links = implicitClassLinks
468473
}
469474

470475
case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context)
@@ -475,9 +480,10 @@ object messages {
475480
val explanation =
476481
hl"""|implicit classes may not be case classes. Instead use a plain class:
477482
|
478-
|implicit class ${cdef.name}...
479-
|
480-
|""" + implicitClassRestrictionsText
483+
|${"implicit class"} ${cdef.name}...
484+
|"""
485+
486+
override def links = implicitClassLinks
481487
}
482488

483489
case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context)
@@ -541,17 +547,19 @@ object messages {
541547
val kind = "Syntax"
542548
val msg = "error in interpolated string: identifier or block expected"
543549
val explanation = {
544-
val code1 = "s\"$new Point(0, 0)\""
545-
val code2 = "s\"${new Point(0, 0)}\""
546550
hl"""|This usually happens when you forget to place your expressions inside curly braces.
547551
|
548-
|$code1
552+
|${"s\"$new Point(0, 0)\""}
549553
|
550554
|should be written as
551555
|
552-
|$code2
556+
|${"s\"${new Point(0, 0)}\""}
553557
|"""
554558
}
559+
560+
override def links = List(
561+
TourUrl("More on String Interpolation", "core/string-interpolation.html")
562+
)
555563
}
556564

557565
case class UnboundPlaceholderParameter()(implicit ctx:Context)
@@ -1715,19 +1723,13 @@ object messages {
17151723
val kind = "Syntax"
17161724
val msg = s"modifier(s) `$flags' not allowed for ${printableType.getOrElse("combination")}"
17171725
val explanation = {
1718-
val first = "sealed def y: Int = 1"
1719-
val second = "sealed lazy class z"
17201726
hl"""You tried to use a modifier that is inapplicable for the type of item under modification
1721-
|
1722-
| Please see the official Scala Language Specification section on modifiers:
1723-
| https://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#modifiers
17241727
|
17251728
|Consider the following example:
1726-
|$first
1729+
|${"sealed def y: Int = 1"}
17271730
|In this instance, the modifier 'sealed' is not applicable to the item type 'def' (method)
1728-
|$second
1729-
|In this instance, the modifier combination is not supported
1730-
"""
1731+
|${"sealed lazy class z"}
1732+
|In this instance, the modifier combination is not supported"""
17311733
}
17321734

17331735
override def links: List[DocumentationLink] = List(

compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,4 @@ trait ErrorMessagesTest extends DottyTest {
4444
}
4545
}
4646

47-
def assertMessageCount(expected: Int, messages: List[Message]): Unit =
48-
assertEquals(messages.mkString,
49-
expected,
50-
messages.length
51-
)
5247
}

0 commit comments

Comments
 (0)