diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 04f430f780bb..bd26a4ff038d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1680,18 +1680,13 @@ object Parsers { ) def addFlag(mods: Modifiers, flag: FlagSet): Modifiers = { - def incompatible(kind: String) = { - syntaxError(ModifiersNotAllowed(mods.flags, kind)) - Modifiers(flag) - } + def getPrintableTypeFromFlagSet = + Map(Trait -> "trait", Method -> "method", Mutable -> "variable").get(flag) + if (compatible(mods.flags, flag)) mods | flag - else flag match { - case Trait => incompatible("trait") - case Method => incompatible("method") - case Mutable => incompatible("variable") - case _ => - syntaxError(s"illegal modifier combination: ${mods.flags} and $flag") - mods + else { + syntaxError(ModifiersNotAllowed(mods.flags, getPrintableTypeFromFlagSet)) + Modifiers(flag) } } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index ada7c2cab642..610ce2a17f77 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -1648,18 +1648,23 @@ object messages { val explanation = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." } - case class ModifiersNotAllowed(flags: FlagSet, sort: String)(implicit ctx: Context) + case class ModifiersNotAllowed(flags: FlagSet, printableType: Option[String])(implicit ctx: Context) extends Message(ModifiersNotAllowedID) { val kind = "Syntax" - val msg = s"modifier(s) `$flags' not allowed for $sort" + val msg = s"modifier(s) `$flags' not allowed for ${printableType.getOrElse("combination")}" val explanation = { - val code = "sealed def y: Int = 1" + val first = "sealed def y: Int = 1" + val second = "sealed lazy class z" hl"""You tried to use a modifier that is inapplicable for the type of item under modification | + | Please see the official Scala Language Specification section on modifiers: + | https://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#modifiers | |Consider the following example: - |$code + |$first |In this instance, the modifier 'sealed' is not applicable to the item type 'def' (method) + |$second + |In this instance, the modifier combination is not supported """ } } diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index 2c07738ca334..a36f34a1fa80 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -4,6 +4,8 @@ package reporting import core.Contexts.Context import diagnostic.messages._ +import dotty.tools.dotc.core.Flags +import dotty.tools.dotc.core.Flags.FlagSet import dotty.tools.dotc.core.Types.WildcardType import dotty.tools.dotc.parsing.Tokens import org.junit.Assert._ @@ -841,14 +843,22 @@ class ErrorMessagesTests extends ErrorMessagesTest { } @Test def modifiersNotAllowed = - checkMessagesAfter("refchecks")("""lazy trait T""") + verifyModifiersNotAllowed("lazy trait T", "lazy", Some("trait")) + + @Test def modifiersOtherThanTraitMethodVariable = + verifyModifiersNotAllowed("sealed lazy class x", "sealed") + + private def verifyModifiersNotAllowed(code: String, modifierAssertion: String, + typeAssertion: Option[String] = None) = { + checkMessagesAfter("refchecks")(code) .expect { (ictx, messages) => implicit val ctx: Context = ictx assertMessageCount(1, messages) val ModifiersNotAllowed(flags, sort) :: Nil = messages - assertEquals("lazy", flags.toString) - assertEquals("trait", sort) + assertEquals(modifierAssertion, flags.toString) + assertEquals(typeAssertion, sort) } + } @Test def wildcardOnTypeArgumentNotAllowedOnNew = checkMessagesAfter("refchecks") {