Skip to content

Commit 24a8ba1

Browse files
committed
Port all Desugar errors to new scheme
1 parent 2cf21e8 commit 24a8ba1

10 files changed

+119
-6
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

+6-5
Original file line numberDiff line numberDiff line change
@@ -946,9 +946,11 @@ object desugar {
946946
}
947947
case mdef: Import =>
948948
mdef
949-
case mdef =>
949+
case mdef if !mdef.isEmpty => {
950950
ctx.error(ExtensionCanOnlyHaveDefs(mdef), mdef.sourcePos)
951951
mdef
952+
}
953+
case mdef => mdef
952954
}
953955
}
954956

@@ -1001,7 +1003,7 @@ object desugar {
10011003
case Some(DefDef(name, _, (vparam :: _) :: _, _, _)) =>
10021004
s"extension_${name}_${inventTypeName(vparam.tpt)}"
10031005
case _ =>
1004-
ctx.error(i"anonymous instance must implement a type or have at least one extension method", impl.sourcePos)
1006+
ctx.error(AnonymousInstanceCannotBeEmpty(impl), impl.sourcePos)
10051007
nme.ERROR.toString
10061008
else
10071009
impl.parents.map(inventTypeName(_)).mkString("given_", "_", "")
@@ -1173,10 +1175,9 @@ object desugar {
11731175
def checkModifiers(tree: Tree)(implicit ctx: Context): Tree = tree match {
11741176
case tree: MemberDef =>
11751177
var tested: MemberDef = tree
1176-
def fail(msg: String) = ctx.error(msg, tree.sourcePos)
11771178
def checkApplicable(flag: Flag, test: MemberDefTest): Unit =
11781179
if (tested.mods.is(flag) && !test.applyOrElse(tree, (md: MemberDef) => false)) {
1179-
fail(i"modifier `${flag.flagsString}` is not allowed for this definition")
1180+
ctx.error(ModifierNotAllowedForDefinition(flag), tree.sourcePos)
11801181
tested = tested.withMods(tested.mods.withoutFlags(flag))
11811182
}
11821183
checkApplicable(Opaque, legalOpaque)
@@ -1798,7 +1799,7 @@ object desugar {
17981799
def traverse(tree: untpd.Tree)(implicit ctx: Context): Unit = tree match {
17991800
case Splice(expr) => collect(expr)
18001801
case TypSplice(expr) =>
1801-
ctx.error("Type splices cannot be used in val patterns. Consider using `match` instead.", tree.sourcePos)
1802+
ctx.error(TypeSpliceInValPattern(expr), tree.sourcePos)
18021803
case _ => traverseChildren(tree)
18031804
}
18041805
}.traverse(expr)

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

+4-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,10 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] {
161161
NoExtensionMethodAllowedID,
162162
ExtensionMethodCannotHaveTypeParamsID,
163163
ExtensionCanOnlyHaveDefsID,
164-
UnexpectedPatternForSummonFromID
164+
UnexpectedPatternForSummonFromID,
165+
AnonymousInstanceCannotBeEmptyID,
166+
TypeSpliceInValPatternID,
167+
ModifierNotAllowedForDefinitionID
165168

166169
def errorNumber = ordinal - 2
167170
}

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

+30
Original file line numberDiff line numberDiff line change
@@ -2526,4 +2526,34 @@ object messages {
25262526
| }
25272527
|""".stripMargin
25282528
}
2529+
2530+
case class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context)
2531+
extends Message(AnonymousInstanceCannotBeEmptyID) {
2532+
val kind: String = "Syntax"
2533+
val msg: String = i"anonymous instance must implement a type or have at least one extension method"
2534+
2535+
val explanation: String =
2536+
em"""|Anonymous instances cannot be defined with an empty body. The block
2537+
|`${impl.show}` should either contain an implemented type or at least one extension method.
2538+
|""".stripMargin
2539+
}
2540+
2541+
case class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context)
2542+
extends Message(TypeSpliceInValPatternID) {
2543+
val kind: String = "Syntax"
2544+
val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead."
2545+
2546+
val explanation: String =
2547+
em"""|Type splice: `$$${expr.show}` cannot be used in a `val` pattern. Consider rewriting the `val` pattern
2548+
|as a `match` with a corresponding `case` to replace the `val`.
2549+
|""".stripMargin
2550+
}
2551+
2552+
case class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context)
2553+
extends Message(ModifierNotAllowedForDefinitionID) {
2554+
val kind: String = "Syntax"
2555+
val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition"
2556+
2557+
val explanation: String = ""
2558+
}
25292559
}

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

+50
Original file line numberDiff line numberDiff line change
@@ -1893,4 +1893,54 @@ class ErrorMessagesTests extends ErrorMessagesTest {
18931893
assertEquals("Only methods allowed here, since collective parameters are given", errorMsg)
18941894
assertEquals("val v: T = t", x.show)
18951895
}
1896+
1897+
@Test def anonymousInstanceMustImplementAType =
1898+
checkMessagesAfter(RefChecks.name) {
1899+
"""object Test {
1900+
| extension on[T] (t: T) { }
1901+
|}
1902+
""".stripMargin
1903+
}
1904+
.expect { (ictx, messages)
1905+
implicit val ctx: Context = ictx
1906+
assertMessageCount(1, messages)
1907+
val errorMsg = messages.head.msg
1908+
assertEquals("anonymous instance must implement a type or have at least one extension method", errorMsg)
1909+
}
1910+
1911+
@Test def typeSplicesInValPatterns =
1912+
checkMessagesAfter(RefChecks.name) {
1913+
s"""import scala.quoted._
1914+
|object Foo {
1915+
| def f(using q: QuoteContext) = {
1916+
| val t: Type[Int] = ???
1917+
| val '[ *:[$$t] ] = ???
1918+
| }
1919+
|}
1920+
""".stripMargin
1921+
}
1922+
.expect { (ictx, messages)
1923+
implicit val ctx: Context = ictx
1924+
assertMessageCount(1, messages)
1925+
val errorMsg = messages.head.msg
1926+
val TypeSpliceInValPattern(x) :: Nil = messages
1927+
assertEquals("Type splices cannot be used in val patterns. Consider using `match` instead.", errorMsg)
1928+
assertEquals("t", x.show)
1929+
}
1930+
1931+
@Test def modifierNotAllowedForDefinition =
1932+
checkMessagesAfter(RefChecks.name) {
1933+
"""object Test {
1934+
| opaque def o: Int = 3
1935+
|}
1936+
""".stripMargin
1937+
}
1938+
.expect { (ictx, messages)
1939+
implicit val ctx: Context = ictx
1940+
assertMessageCount(1, messages)
1941+
val errorMsg = messages.head.msg
1942+
val ModifierNotAllowedForDefinition(x) :: Nil = messages
1943+
assertEquals("Modifier `opaque` is not allowed for this definition", errorMsg)
1944+
assertEquals("opaque", x.flagsString)
1945+
}
18961946
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E154] Syntax Error: tests/neg/anonymous-instance-cannot-be-empty.scala:2:15 ----------------------------------------
2+
2 | extension on[T] (t: T) { } // error
3+
| ^^^^^^^^
4+
| anonymous instance must implement a type or have at least one extension method
5+
6+
longer explanation available when compiling with `-explain`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
extension on[T] (t: T) { } // error
3+
}

tests/neg/modifier-not-allowed.check

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
-- [E156] Syntax Error: tests/neg/modifier-not-allowed.scala:2:13 ------------------------------------------------------
2+
2 | opaque def o: Int = 3 // error
3+
| ^^^^^^^^^^^^^^^^^^^^^
4+
| Modifier `opaque` is not allowed for this definition

tests/neg/modifier-not-allowed.scala

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object Test {
2+
opaque def o: Int = 3 // error
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- [E155] Syntax Error: tests/neg/type-splice-in-val-pattern.scala:5:14 ------------------------------------------------
2+
5 | val '[ *:[$$t] ] = ??? // error
3+
| ^^^
4+
| Type splices cannot be used in val patterns. Consider using `match` instead.
5+
6+
longer explanation available when compiling with `-explain`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import scala.quoted._
2+
object Foo {
3+
def f(using q: QuoteContext) = {
4+
val t: Type[Int] = ???
5+
val '[ *:[$$t] ] = ??? // error
6+
}
7+
}

0 commit comments

Comments
 (0)