From f7d374f6f9eea121cc6f9ceb7a8257b96492ef1b Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 24 Mar 2020 17:58:44 +0100 Subject: [PATCH 01/13] Fix performance degradation: make message fields lazy Make field `msg` and `explanation` in Message lazy and make message containers strict. That way, we can look inside a message container to find out what kind of message we are having without fear of forcing too much. --- .../dotc/reporting/diagnostic/Message.scala | 5 +- .../dotc/reporting/diagnostic/messages.scala | 835 +++++++++--------- 2 files changed, 409 insertions(+), 431 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index b3b9a12067ad..37a409d1246d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -12,7 +12,7 @@ object Message { * not yet been ported to the new scheme. Comment out this `implicit def` to * see where old errors still exist */ - implicit def toNoExplanation(str: String): Message = + implicit def toNoExplanation(str: => String): Message = new NoExplanation(str) } @@ -125,7 +125,8 @@ class ExtendMessage(_msg: () => Message)(f: String => String) { self => } /** The fallback `Message` containing no explanation and having no `kind` */ -class NoExplanation(val msg: String) extends Message(ErrorMessageID.NoExplanationID) { +class NoExplanation(msgFn: => String) extends Message(ErrorMessageID.NoExplanationID) { + lazy val msg: String = msgFn val explanation: String = "" val kind: String = "" diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 5b57e7ec8a7e..5decb781f070 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -32,63 +32,63 @@ object messages { // `MessageContainer`s to be consumed by `Reporter` ---------------------- // class Error( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends MessageContainer(msgFn, pos, ERROR) + ) extends MessageContainer(msg, pos, ERROR) /** A sticky error is an error that should not be hidden by backtracking and * trying some alternative path. Typically, errors issued after catching * a TypeError exception are sticky. */ class StickyError( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends Error(msgFn, pos) + ) extends Error(msg, pos) class Warning( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends MessageContainer(msgFn, pos, WARNING) { - def toError: Error = new Error(msgFn, pos) + ) extends MessageContainer(msg, pos, WARNING) { + def toError: Error = new Error(msg, pos) } class Info( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends MessageContainer(msgFn, pos, INFO) + ) extends MessageContainer(msg, pos, INFO) abstract class ConditionalWarning( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends Warning(msgFn, pos) { + ) extends Warning(msg, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] } class FeatureWarning( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { + ) extends ConditionalWarning(msg, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.feature } class UncheckedWarning( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { + ) extends ConditionalWarning(msg, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.unchecked } class DeprecationWarning( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { + ) extends ConditionalWarning(msg, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.deprecation } class MigrationWarning( - msgFn: => Message, + msg: Message, pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { + ) extends ConditionalWarning(msg, pos) { def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.migration } @@ -117,7 +117,7 @@ object messages { // Syntax Errors ---------------------------------------------------------- // abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) extends Message(EmptyCatchOrFinallyBlockID) { - val explanation: String = { + lazy val explanation: String = { val tryString = tryBody match { case Block(Nil, untpd.EmptyTree) => "{}" case _ => tryBody.show @@ -154,7 +154,7 @@ object messages { case class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) { val kind: String = "Syntax" - val msg: String = + lazy val msg: String = em"""|The ${hl("catch")} block does not contain a valid expression, try |adding a case like - ${hl("case e: Exception =>")} to the block""" } @@ -162,7 +162,7 @@ object messages { case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchAndFinallyBlockID) { val kind: String = "Syntax" - val msg: String = + lazy val msg: String = em"""|A ${hl("try")} without ${hl("catch")} or ${hl("finally")} is equivalent to putting |its body in a block; no exceptions are handled.""" } @@ -170,9 +170,9 @@ object messages { case class DeprecatedWithOperator()(implicit ctx: Context) extends Message(DeprecatedWithOperatorID) { val kind: String = "Syntax" - val msg: String = + lazy val msg: String = em"""${hl("with")} as a type operator has been deprecated; use ${hl("&")} instead""" - val explanation: String = + lazy val explanation: String = em"""|Dotty introduces intersection types - ${hl("&")} types. These replace the |use of the ${hl("with")} keyword. There are a few differences in |semantics between intersection types and using ${hl("with")}.""" @@ -181,10 +181,10 @@ object messages { case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(CaseClassMissingParamListID) { val kind: String = "Syntax" - val msg: String = + lazy val msg: String = em"""|A ${hl("case class")} must have at least one parameter list""" - val explanation: String = + lazy val explanation: String = em"""|${cdef.name} must have at least one parameter list, if you would rather |have a singleton representation of ${cdef.name}, use a "${hl("case object")}". |Or, add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""" @@ -198,7 +198,7 @@ object messages { extends Message(AnonymousFunctionMissingParamTypeID) { val kind: String = "Type" - val msg: String = { + lazy val msg: String = { val ofFun = if (MethodType.syntheticParamNames(args.length + 1) contains param.name) i" of expanded function:\n$tree" @@ -214,31 +214,29 @@ object messages { |I could not infer the type of the parameter ${param.name}$ofFun.$inferred""" } - val explanation: String = "" + lazy val explanation: String = "" } case class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) extends Message(WildcardOnTypeArgumentNotAllowedOnNewID) { val kind: String = "Syntax" - val msg: String = "Type argument must be fully defined" - - val code1: String = - """ - |object TyperDemo { - | class Team[A] - | val team = new Team[?] - |} - """.stripMargin - - val code2: String = - """ - |object TyperDemo { - | class Team[A] - | val team = new Team[Int] - |} - """.stripMargin + lazy val msg: String = "Type argument must be fully defined" + lazy val explanation: String = + val code1: String = + """ + |object TyperDemo { + | class Team[A] + | val team = new Team[?] + |} + """.stripMargin - val explanation: String = + val code2: String = + """ + |object TyperDemo { + | class Team[A] + | val team = new Team[Int] + |} + """.stripMargin em"""|Wildcard on arguments is not allowed when declaring a new type. | |Given the following example: @@ -255,9 +253,9 @@ object messages { case class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) extends Message(DuplicateBindID) { val kind: String = "Naming" - val msg: String = em"duplicate pattern variable: ${bind.name}" + lazy val msg: String = em"duplicate pattern variable: ${bind.name}" - val explanation: String = { + lazy val explanation: String = { val pat = tree.pat.show val guard = tree.guard match { case untpd.EmptyTree => "" @@ -282,9 +280,9 @@ object messages { case class MissingIdent(tree: untpd.Ident, treeKind: String, name: Name)(implicit ctx: Context) extends Message(MissingIdentID) { val kind: String = "Unbound Identifier" - val msg: String = em"Not found: $treeKind$name" + lazy val msg: String = em"Not found: $treeKind$name" - val explanation: String = { + lazy val explanation: String = { em"""|The identifier for `$treeKind$name` is not bound, that is, |no declaration for this identifier can be found. |That can happen, for example, if `$name` or its declaration has either been @@ -295,7 +293,7 @@ object messages { case class TypeMismatch(found: Type, expected: Type, whyNoMatch: String = "", implicitFailure: String = "")(implicit ctx: Context) extends Message(TypeMismatchID) { val kind: String = "Type Mismatch" - val msg: String = { + lazy val msg: String = { val (where, printCtx) = Formatting.disambiguateTypes(found, expected) val whereSuffix = if (where.isEmpty) where else s"\n\n$where" val (fnd, exp) = Formatting.typeDiff(found, expected)(printCtx) @@ -303,7 +301,7 @@ object messages { |Required: $exp""".stripMargin + whereSuffix + whyNoMatch + implicitFailure } - val explanation: String = "" + lazy val explanation: String = "" } case class NotAMember(site: Type, name: Name, selected: String, addendum: String = "")(implicit ctx: Context) @@ -312,7 +310,7 @@ object messages { //println(i"site = $site, decls = ${site.decls}, source = ${site.widen.typeSymbol.sourceFile}") //DEBUG - val msg: String = { + lazy val msg: String = { import core.Flags._ val maxDist = 3 // maximal number of differences to be considered for a hint val missing = name.show @@ -364,15 +362,15 @@ object messages { ex"$selected $name is not a member of ${site.widen}$finalAddendum" } - val explanation: String = "" + lazy val explanation: String = "" } case class EarlyDefinitionsNotSupported()(implicit ctx: Context) extends Message(EarlyDefinitionsNotSupportedID) { val kind: String = "Syntax" - val msg: String = "Early definitions are not supported; use trait parameters instead" + lazy val msg: String = "Early definitions are not supported; use trait parameters instead" - val explanation: String = { + lazy val explanation: String = { val code1 = """|trait Logging { | val f: File @@ -416,9 +414,9 @@ object messages { case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(TopLevelImplicitClassID) { val kind: String = "Syntax" - val msg: String = em"""An ${hl("implicit class")} may not be top-level""" + lazy val msg: String = em"""An ${hl("implicit class")} may not be top-level""" - val explanation: String = { + lazy val explanation: String = { val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef val exampleArgs = if(constr0.vparamss.isEmpty) "..." @@ -447,9 +445,9 @@ object messages { case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(ImplicitCaseClassID) { val kind: String = "Syntax" - val msg: String = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" + lazy val msg: String = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" - val explanation: String = + lazy val explanation: String = em"""|Implicit classes may not be case classes. Instead use a plain class: | |implicit class ${cdef.name}... @@ -460,8 +458,8 @@ object messages { case class ImplicitClassPrimaryConstructorArity()(implicit ctx: Context) extends Message(ImplicitClassPrimaryConstructorArityID){ val kind: String = "Syntax" - val msg: String = "Implicit classes must accept exactly one primary constructor parameter" - val explanation: String = { + lazy val msg: String = "Implicit classes must accept exactly one primary constructor parameter" + lazy val explanation: String = { val example = "implicit class RichDate(date: java.util.Date)" em"""Implicit classes may only take one non-implicit argument in their constructor. For example: | @@ -476,9 +474,9 @@ object messages { case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) extends Message(ObjectMayNotHaveSelfTypeID) { val kind: String = "Syntax" - val msg: String = em"""${hl("object")}s must not have a self ${hl("type")}""" + lazy val msg: String = em"""${hl("object")}s must not have a self ${hl("type")}""" - val explanation: String = { + lazy val explanation: String = { val untpd.ModuleDef(name, tmpl) = mdef val ValDef(_, selfTpt, _) = tmpl.self em"""|${hl("object")}s must not have a self ${hl("type")}: @@ -494,9 +492,9 @@ object messages { case class RepeatedModifier(modifier: String)(implicit ctx:Context) extends Message(RepeatedModifierID) { val kind: String = "Syntax" - val msg: String = em"""Repeated modifier $modifier""" + lazy val msg: String = em"""Repeated modifier $modifier""" - val explanation: String = { + lazy val explanation: String = { val code1 = em"""private private val Origin = Point(0, 0)""" val code2 = em"""private final val Origin = Point(0, 0)""" em"""This happens when you accidentally specify the same modifier twice. @@ -516,8 +514,8 @@ object messages { case class InterpolatedStringError()(implicit ctx:Context) extends Message(InterpolatedStringErrorID) { val kind: String = "Syntax" - val msg: String = "Error in interpolated string: identifier or block expected" - val explanation: String = { + lazy val msg: String = "Error in interpolated string: identifier or block expected" + lazy val explanation: String = { val code1 = "s\"$new Point(0, 0)\"" val code2 = "s\"${new Point(0, 0)}\"" em"""|This usually happens when you forget to place your expressions inside curly braces. @@ -534,8 +532,8 @@ object messages { case class UnboundPlaceholderParameter()(implicit ctx:Context) extends Message(UnboundPlaceholderParameterID) { val kind: String = "Syntax" - val msg: String = em"""Unbound placeholder parameter; incorrect use of ${hl("_")}""" - val explanation: String = + lazy val msg: String = em"""Unbound placeholder parameter; incorrect use of ${hl("_")}""" + lazy val explanation: String = em"""|The ${hl("_")} placeholder syntax was used where it could not be bound. |Consider explicitly writing the variable binding. | @@ -570,8 +568,8 @@ object messages { case class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) extends Message(IllegalStartSimpleExprID) { val kind: String = "Syntax" - val msg: String = em"expression expected but ${Red(illegalToken)} found" - val explanation: String = { + lazy val msg: String = em"expression expected but ${Red(illegalToken)} found" + lazy val explanation: String = { em"""|An expression cannot start with ${Red(illegalToken)}.""" } } @@ -579,8 +577,8 @@ object messages { case class MissingReturnType()(implicit ctx:Context) extends Message(MissingReturnTypeID) { val kind: String = "Syntax" - val msg: String = "Missing return type" - val explanation: String = + lazy val msg: String = "Missing return type" + lazy val explanation: String = em"""|An abstract declaration must have a return type. For example: | |trait Shape {hl( @@ -591,8 +589,8 @@ object messages { case class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) extends Message(MissingReturnTypeWithReturnStatementID) { val kind: String = "Syntax" - val msg: String = em"$method has a return statement; it needs a result type" - val explanation: String = + lazy val msg: String = em"$method has a return statement; it needs a result type" + lazy val explanation: String = em"""|If a method contains a ${hl("return")} statement, it must have an |explicit return type. For example: | @@ -602,9 +600,9 @@ object messages { case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) extends Message(YieldOrDoExpectedInForComprehensionID) { val kind: String = "Syntax" - val msg: String = em"${hl("yield")} or ${hl("do")} expected" + lazy val msg: String = em"${hl("yield")} or ${hl("do")} expected" - val explanation: String = + lazy val explanation: String = em"""|When the enumerators in a for comprehension are not placed in parentheses or |braces, a ${hl("do")} or ${hl("yield")} statement is required after the enumerators |section of the comprehension. @@ -635,9 +633,9 @@ object messages { case class ProperDefinitionNotFound()(implicit ctx: Context) extends Message(ProperDefinitionNotFoundID) { val kind: String = "Definition Not Found" - val msg: String = em"""Proper definition was not found in ${hl("@usecase")}""" + lazy val msg: String = em"""Proper definition was not found in ${hl("@usecase")}""" - val explanation: String = { + lazy val explanation: String = { val noUsecase = "def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That" @@ -674,9 +672,9 @@ object messages { case class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) extends Message(ByNameParameterNotSupportedID) { val kind: String = "Syntax" - val msg: String = em"By-name parameter type ${tpe} not allowed here." + lazy val msg: String = em"By-name parameter type ${tpe} not allowed here." - val explanation: String = + lazy val explanation: String = em"""|By-name parameters act like functions that are only evaluated when referenced, |allowing for lazy evaluation of a parameter. | @@ -703,29 +701,21 @@ object messages { private val actualCount = actual.length private val msgPrefix = if (actualCount > expectedCount) "Too many" else "Not enough" - //TODO add def simpleParamName to ParamInfo - private val expectedArgString = expectedArgs - .map(_.paramName.unexpandedName.show) - .mkString("[", ", ", "]") - - private val actualArgString = actual.map(_.show).mkString("[", ", ", "]") - - private val prettyName = - try - fntpe.termSymbol match { + lazy val msg: String = + val expectedArgString = expectedArgs + .map(_.paramName.unexpandedName.show) + .mkString("[", ", ", "]") + val actualArgString = actual.map(_.show).mkString("[", ", ", "]") + val prettyName = + try fntpe.termSymbol match case NoSymbol => fntpe.show case symbol => symbol.showFullName - } - catch { - case NonFatal(ex) => fntpe.show - } - - val msg: String = + catch case NonFatal(ex) => fntpe.show em"""|$msgPrefix type arguments for $prettyName$expectedArgString |expected: $expectedArgString |actual: $actualArgString""".stripMargin - val explanation: String = { + lazy val explanation: String = { val tooManyTypeParams = """|val tuple2: (Int, String) = (1, "one") |val list: List[(Int, String)] = List(tuple2)""".stripMargin @@ -748,8 +738,8 @@ object messages { case class IllegalVariableInPatternAlternative()(implicit ctx: Context) extends Message(IllegalVariableInPatternAlternativeID) { val kind: String = "Syntax" - val msg: String = "Variables are not allowed in alternative patterns" - val explanation: String = { + lazy val msg: String = "Variables are not allowed in alternative patterns" + lazy val explanation: String = { val varInAlternative = """|def g(pair: (Int,Int)): Int = pair match { | case (1, n) | (n, 1) => n @@ -777,8 +767,8 @@ object messages { case class IdentifierExpected(identifier: String)(implicit ctx: Context) extends Message(IdentifierExpectedID) { val kind: String = "Syntax" - val msg: String = "identifier expected" - val explanation: String = { + lazy val msg: String = "identifier expected" + lazy val explanation: String = { val wrongIdentifier = em"def foo: $identifier = {...}" val validIdentifier = em"def foo = {...}" em"""|An identifier expected, but $identifier found. This could be because @@ -798,8 +788,8 @@ object messages { case class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) extends Message(AuxConstructorNeedsNonImplicitParameterID) { val kind: String = "Syntax" - val msg: String = "Auxiliary constructor needs non-implicit parameter list" - val explanation: String = + lazy val msg: String = "Auxiliary constructor needs non-implicit parameter list" + lazy val explanation: String = em"""|Only the primary constructor is allowed an ${hl("implicit")} parameter list; |auxiliary constructors need non-implicit parameter lists. When a primary |constructor has an implicit argslist, auxiliary constructors that call the @@ -814,8 +804,8 @@ object messages { case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) extends Message(IncorrectRepeatedParameterSyntaxID) { val kind: String = "Syntax" - val msg: String = "'*' expected" - val explanation: String = + lazy val msg: String = "'*' expected" + lazy val explanation: String = em"""|Expected * in ${hl("_*")} operator. | |The ${hl("_*")} operator can be used to supply a sequence-based argument @@ -841,8 +831,8 @@ object messages { case class IllegalLiteral()(implicit ctx: Context) extends Message(IllegalLiteralID) { val kind: String = "Syntax" - val msg: String = "Illegal literal" - val explanation: String = + lazy val msg: String = "Illegal literal" + lazy val explanation: String = em"""|Available literals can be divided into several groups: | - Integer literals: 0, 21, 0xFFFFFFFF, -42L | - Floating Point Literals: 0.0, 1e30f, 3.14159f, 1.0e-100, .1 @@ -856,13 +846,13 @@ object messages { case class PatternMatchExhaustivity(uncovered: String)(implicit ctx: Context) extends Message(PatternMatchExhaustivityID) { val kind: String = "Pattern Match Exhaustivity" - val msg: String = + lazy val msg: String = em"""|${hl("match")} may not be exhaustive. | |It would fail on pattern case: $uncovered""" - val explanation: String = + lazy val explanation: String = em"""|There are several ways to make the match exhaustive: | - Add missing cases as shown in the warning | - If an extractor always return ${hl("Some(...)")}, write ${hl("Some[X]")} for its return type @@ -874,7 +864,7 @@ object messages { extends Message(UncheckedTypePatternID) { val kind: String = "Pattern Match Exhaustivity" - val explanation: String = + lazy val explanation: String = em"""|Type arguments and type refinements are erased during compile time, thus it's |impossible to check them at run-time. | @@ -885,22 +875,22 @@ object messages { case class MatchCaseUnreachable()(implicit ctx: Context) extends Message(MatchCaseUnreachableID) { val kind: String = "Match case Unreachable" - val msg: String = "Unreachable case" - val explanation: String = "" + lazy val msg: String = "Unreachable case" + lazy val explanation: String = "" } case class MatchCaseOnlyNullWarning()(implicit ctx: Context) extends Message(MatchCaseOnlyNullWarningID) { val kind: String = "Only null matched" - val msg: String = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" - val explanation: String = "" + lazy val msg: String = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" + lazy val explanation: String = "" } case class SeqWildcardPatternPos()(implicit ctx: Context) extends Message(SeqWildcardPatternPosID) { val kind: String = "Syntax" - val msg: String = em"""${hl("_*")} can be used only for last argument""" - val explanation: String = { + lazy val msg: String = em"""${hl("_*")} can be used only for last argument""" + lazy val explanation: String = { val code = """def sumOfTheFirstTwo(list: List[Int]): Int = list match { | case List(first, second, x:_*) => first + second @@ -923,8 +913,8 @@ object messages { case class IllegalStartOfSimplePattern()(implicit ctx: Context) extends Message(IllegalStartOfSimplePatternID) { val kind: String = "Syntax" - val msg: String = "pattern expected" - val explanation: String = { + lazy val msg: String = "pattern expected" + lazy val explanation: String = { val sipCode = """def f(x: Int, y: Int) = x match { | case `y` => ... @@ -1003,17 +993,17 @@ object messages { case class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) extends Message(PkgDuplicateSymbolID) { val kind: String = "Duplicate Symbol" - val msg: String = em"Trying to define package with same name as $existing" - val explanation: String = "" + lazy val msg: String = em"Trying to define package with same name as $existing" + lazy val explanation: String = "" } case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) extends Message(ExistentialTypesNoLongerSupportedID) { val kind: String = "Syntax" - val msg: String = + lazy val msg: String = em"""|Existential types are no longer supported - |use a wildcard or dependent type instead""" - val explanation: String = + lazy val explanation: String = em"""|The use of existential types is no longer supported. | |You should use a wildcard or dependent type instead. @@ -1033,8 +1023,8 @@ object messages { case class UnboundWildcardType()(implicit ctx: Context) extends Message(UnboundWildcardTypeID) { val kind: String = "Syntax" - val msg: String = "Unbound wildcard type" - val explanation: String = + lazy val msg: String = "Unbound wildcard type" + lazy val explanation: String = em"""|The wildcard type syntax (${hl("_")}) was used where it could not be bound. |Replace ${hl("_")} with a non-wildcard type. If the type doesn't matter, |try replacing ${hl("_")} with ${hl("Any")}. @@ -1077,26 +1067,22 @@ object messages { case class DanglingThisInPath()(implicit ctx: Context) extends Message(DanglingThisInPathID) { val kind: String = "Syntax" - val msg: String = em"""Expected an additional member selection after the keyword ${hl("this")}""" - - val contextCode: String = - """ trait Outer { - | val member: Int - | type Member - | trait Inner { - | ... - | } - | }""" - - val importCode: String = - """ import Outer.this.member - | // ^^^^^^^""" - - val typeCode: String = - """ type T = Outer.this.Member - | // ^^^^^^^""" - - val explanation: String = + lazy val msg: String = em"""Expected an additional member selection after the keyword ${hl("this")}""" + lazy val explanation: String = + val contextCode: String = + """ trait Outer { + | val member: Int + | type Member + | trait Inner { + | ... + | } + | }""" + val importCode: String = + """ import Outer.this.member + | // ^^^^^^^""" + val typeCode: String = + """ type T = Outer.this.Member + | // ^^^^^^^""" em"""|Paths of imports and type selections must not end with the keyword ${hl("this")}. | |Maybe you forgot to select a member of ${hl("this")}? As an example, in the @@ -1114,9 +1100,9 @@ object messages { case class OverridesNothing(member: Symbol)(implicit ctx: Context) extends Message(OverridesNothingID) { val kind: String = "Reference" - val msg: String = em"""${member} overrides nothing""" + lazy val msg: String = em"""${member} overrides nothing""" - val explanation: String = + lazy val explanation: String = em"""|There must be a field or method with the name ${member.name} in a super |class of ${member.owner} to override it. Did you misspell it? |Are you extending the right classes? @@ -1126,11 +1112,9 @@ object messages { case class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) extends Message(OverridesNothingButNameExistsID) { val kind: String = "Reference" - val msg: String = em"""${member} has a different signature than the overridden declaration""" - - val existingDecl: String = existing.map(_.showDcl).mkString(" \n") - - val explanation: String = + lazy val msg: String = em"""${member} has a different signature than the overridden declaration""" + lazy val explanation: String = + val existingDecl: String = existing.map(_.showDcl).mkString(" \n") em"""|There must be a non-final field or method with the name ${member.name} and the |same parameter list in a super class of ${member.owner} to override it. | @@ -1145,9 +1129,9 @@ object messages { case class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) extends Message(ForwardReferenceExtendsOverDefinitionID) { val kind: String = "Reference" - val msg: String = em"${definition.name} is a forward reference extending over the definition of ${value.name}" + lazy val msg: String = em"${definition.name} is a forward reference extending over the definition of ${value.name}" - val explanation: String = + lazy val explanation: String = em"""|${definition.name} is used before you define it, and the definition of ${value.name} |appears between that use and the definition of ${definition.name}. | @@ -1165,30 +1149,30 @@ object messages { extends Message(ExpectedTokenButFoundID) { val kind: String = "Syntax" - private val expectedText = - if (Tokens.isIdentifier(expected)) "an identifier" - else Tokens.showToken(expected) - - private val foundText = Tokens.showToken(found) + private lazy val foundText = Tokens.showToken(found) - val msg: String = em"""${expectedText} expected, but ${foundText} found""" + lazy val msg: String = + val expectedText = + if (Tokens.isIdentifier(expected)) "an identifier" + else Tokens.showToken(expected) + em"""${expectedText} expected, but ${foundText} found""" - private val ifKeyword = + lazy val explanation: String = if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found)) s""" - |If you necessarily want to use $foundText as identifier, you may put it in backticks.""".stripMargin + |If you want to use $foundText as identifier, you may put it in backticks: `$foundText`.""".stripMargin else "" - val explanation: String = s"$ifKeyword" } case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) extends Message(MixedLeftAndRightAssociativeOpsID) { val kind: String = "Syntax" - val op1Asso: String = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" - val op2Asso: String = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" - val msg: String = em"${op1} (${op1Asso}) and ${op2} ($op2Asso) have same precedence and may not be mixed" - val explanation: String = + lazy val msg: String = + val op1Asso: String = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" + val op2Asso: String = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" + em"${op1} (${op1Asso}) and ${op2} ($op2Asso) have same precedence and may not be mixed" + lazy val explanation: String = s"""|The operators ${op1} and ${op2} are used as infix operators in the same expression, |but they bind to different sides: |${op1} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} @@ -1219,9 +1203,9 @@ object messages { case class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) extends Message(CantInstantiateAbstractClassOrTraitID) { val kind: String = "Usage" - private val traitOrAbstract = if (isTrait) em"a trait" else em"abstract" - val msg: String = em"""${cls.name} is ${traitOrAbstract}; it cannot be instantiated""" - val explanation: String = + private val traitOrAbstract = if (isTrait) "a trait" else "abstract" + lazy val msg: String = em"""${cls.name} is ${traitOrAbstract}; it cannot be instantiated""" + lazy val explanation: String = em"""|Abstract classes and traits need to be extended by a concrete class or object |to make their functionality accessible. | @@ -1237,8 +1221,8 @@ object messages { case class UnreducibleApplication(tycon: Type)(using Context) extends Message(UnreducibleApplicationID): val kind = "Type" - val msg = em"unreducible application of higher-kinded type $tycon to wildcard arguments" - val explanation = + lazy val msg = em"unreducible application of higher-kinded type $tycon to wildcard arguments" + lazy val explanation = em"""|An abstract type constructor cannot be applied to wildcard arguments. |Such applications are equivalent to existential types, which are not |supported in Scala 3.""" @@ -1246,8 +1230,8 @@ object messages { case class OverloadedOrRecursiveMethodNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) { val kind: String = "Cyclic" - val msg: String = em"""Overloaded or recursive $cycleSym needs return type""" - val explanation: String = + lazy val msg: String = em"""Overloaded or recursive $cycleSym needs return type""" + lazy val explanation: String = em"""Case 1: $cycleSym is overloaded |If there are multiple methods named $cycleSym and at least one definition of |it calls another, you need to specify the calling method's return type. @@ -1261,8 +1245,8 @@ object messages { case class RecursiveValueNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) extends Message(RecursiveValueNeedsResultTypeID) { val kind: String = "Cyclic" - val msg: String = em"""Recursive $cycleSym needs type""" - val explanation: String = + lazy val msg: String = em"""Recursive $cycleSym needs type""" + lazy val explanation: String = em"""The definition of $cycleSym is recursive and you need to specify its type. |""".stripMargin } @@ -1270,9 +1254,10 @@ object messages { case class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) extends Message(CyclicReferenceInvolvingID) { val kind: String = "Cyclic" - val where = if denot.exists then s" involving $denot" else "" - val msg: String = em"Cyclic reference $where" - val explanation: String = + lazy val msg: String = + val where = if denot.exists then s" involving $denot" else "" + em"Cyclic reference$where" + lazy val explanation: String = em"""|$denot is declared as part of a cycle which makes it impossible for the |compiler to decide upon ${denot.name}'s type. |To avoid this error, try giving ${denot.name} an explicit type. @@ -1282,8 +1267,8 @@ object messages { case class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) extends Message(CyclicReferenceInvolvingImplicitID) { val kind: String = "Cyclic" - val msg: String = em"""Cyclic reference involving implicit $cycleSym""" - val explanation: String = + lazy val msg: String = em"""Cyclic reference involving implicit $cycleSym""" + lazy val explanation: String = em"""|$cycleSym is declared as part of a cycle which makes it impossible for the |compiler to decide upon ${cycleSym.name}'s type. |This might happen when the right hand-side of $cycleSym's definition involves an implicit search. @@ -1293,13 +1278,10 @@ object messages { case class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(implicit ctx: Context) extends Message(SuperQualMustBeParentID) { - - val msg: String = em"""|$qual does not name a parent of $cls""" val kind: String = "Reference" - - private val parents: Seq[String] = (cls.info.parents map (_.typeSymbol.name.show)).sorted - - val explanation: String = + lazy val msg: String = em"""|$qual does not name a parent of $cls""" + lazy val explanation: String = + val parents: Seq[String] = (cls.info.parents map (_.typeSymbol.name.show)).sorted em"""|When a qualifier ${hl("T")} is used in a ${hl("super")} prefix of the form ${hl("C.super[T]")}, |${hl("T")} must be a parent type of ${hl("C")}. | @@ -1310,9 +1292,9 @@ object messages { case class VarArgsParamMustComeLast()(implicit ctx: Context) extends Message(IncorrectRepeatedParameterSyntaxID) { - val msg: String = em"""${hl("varargs")} parameter must come last""" val kind: String = "Syntax" - val explanation: String = + lazy val msg: String = em"""${hl("varargs")} parameter must come last""" + lazy val explanation: String = em"""|The ${hl("varargs")} field must be the last field in the method signature. |Attempting to define a field in a method signature after a ${hl("varargs")} field is an error. |""" @@ -1341,15 +1323,14 @@ object messages { ex"""$howVisible$qualifier in ${em"${whereFound.owner}"}""" } + val kind: String = "Reference" - val msg: String = + lazy val msg: String = i"""|Reference to ${em"$name"} is ambiguous |it is both ${bindingString(newPrec, ctx)} |and ${bindingString(prevPrec, prevCtx, " subsequently")}""" - val kind: String = "Reference" - - val explanation: String = + lazy val explanation: String = em"""|The compiler can't decide which of the possible choices you |are referencing with $name. |Note: @@ -1366,14 +1347,14 @@ object messages { def methodSymbol: Symbol = tpd.methPart(tree).symbol - val msg: String = { + lazy val msg: String = { val more = if (tree.isInstanceOf[tpd.Apply]) " more" else "" val meth = methodSymbol val methStr = if (meth.exists) methodSymbol.showLocated else "expression" em"$methStr does not take$more parameters" } - val explanation: String = { + lazy val explanation: String = { val isNullary = methodSymbol.info.isInstanceOf[ExprType] val addendum = if (isNullary) "\nNullary methods may not be called with parenthesis" @@ -1388,13 +1369,13 @@ object messages { err: Errors)( implicit ctx: Context) extends Message(AmbiguousOverloadID) { + val kind: String = "Reference" - private val all = if (alts.length == 2) "both" else "all" - val msg: String = + private def all = if (alts.length == 2) "both" else "all" + lazy val msg: String = s"""|Ambiguous overload. The ${err.overloadedAltsStr(alts)} |$all match ${err.expectedTypeStr(pt)}""".stripMargin - val kind: String = "Reference" - val explanation: String = + lazy val explanation: String = em"""|There are ${alts.length} methods that could be referenced as the compiler knows too little |about the expected type. |You may specify the expected type e.g. by @@ -1406,8 +1387,8 @@ object messages { case class ReassignmentToVal(name: Name)(implicit ctx: Context) extends Message(ReassignmentToValID) { val kind: String = "Reference" - val msg: String = em"""Reassignment to val $name""" - val explanation: String = + lazy val msg: String = em"""Reassignment to val $name""" + lazy val explanation: String = em"""|You can not assign a new value to $name as values can't be changed. |Keep in mind that every statement has a value, so you may e.g. use | ${hl("val")} $name ${hl("= if (condition) 2 else 5")} @@ -1420,13 +1401,11 @@ object messages { case class TypeDoesNotTakeParameters(tpe: Type, params: List[Trees.Tree[Trees.Untyped]])(implicit ctx: Context) extends Message(TypeDoesNotTakeParametersID) { val kind: String = "Reference" - val msg: String = em"$tpe does not take type parameters" - - private val ps = - if (params.size == 1) s"a type parameter ${params.head}" - else s"type parameters ${params.map(_.show).mkString(", ")}" - - val explanation: String = + lazy val msg: String = em"$tpe does not take type parameters" + lazy val explanation: String = + val ps = + if (params.size == 1) s"a type parameter ${params.head}" + else s"type parameters ${params.map(_.show).mkString(", ")}" i"""You specified ${NoColor(ps)} for ${em"$tpe"}, which is not |declared to take any. |""" @@ -1434,9 +1413,9 @@ object messages { case class ParameterizedTypeLacksArguments(psym: Symbol)(implicit ctx: Context) extends Message(ParameterizedTypeLacksArgumentsID) { - val msg: String = em"Parameterized $psym lacks argument list" val kind: String = "Reference" - val explanation: String = + lazy val msg: String = em"Parameterized $psym lacks argument list" + lazy val explanation: String = em"""The $psym is declared with non-implicit parameters, you may not leave |out the parameter list when extending it. |""" @@ -1444,10 +1423,10 @@ object messages { case class VarValParametersMayNotBeCallByName(name: TermName, mutable: Boolean)(implicit ctx: Context) extends Message(VarValParametersMayNotBeCallByNameID) { - val varOrVal = if (mutable) em"${hl("var")}" else em"${hl("val")}" - val msg: String = s"$varOrVal parameters may not be call-by-name" val kind: String = "Syntax" - val explanation: String = + def varOrVal = if (mutable) em"${hl("var")}" else em"${hl("val")}" + lazy val msg: String = s"$varOrVal parameters may not be call-by-name" + lazy val explanation: String = em"""${hl("var")} and ${hl("val")} parameters of classes and traits may no be call-by-name. In case you |want the parameter to be evaluated on demand, consider making it just a parameter |and a ${hl("def")} in the class such as @@ -1459,38 +1438,38 @@ object messages { case class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) extends Message(MissingTypeParameterForID) { - val msg: String = + val kind: String = "Syntax" + lazy val msg: String = if (tpe.derivesFrom(defn.AnyKindClass)) em"${tpe} cannot be used as a value type" else em"Missing type parameter for ${tpe}" - val kind: String = "Syntax" - val explanation: String = "" + lazy val explanation: String = "" } case class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) extends Message(MissingTypeParameterInTypeAppID) { - val numParams = tpe.typeParams.length - val parameters = if (numParams == 1) "parameter" else "parameters" - val msg: String = em"Missing type $parameters for $tpe" val kind: String = "Type Mismatch" - val explanation: String = em"A fully applied type is expected but $tpe takes $numParams $parameters" + def numParams = tpe.typeParams.length + def parameters = if (numParams == 1) "parameter" else "parameters" + lazy val msg: String = em"Missing type $parameters for $tpe" + lazy val explanation: String = em"A fully applied type is expected but $tpe takes $numParams $parameters" } case class DoesNotConformToBound(tpe: Type, which: String, bound: Type)( err: Errors)(implicit ctx: Context) extends Message(DoesNotConformToBoundID) { - val msg: String = em"Type argument ${tpe} does not conform to $which bound $bound${err.whyNoMatchStr(tpe, bound)}" val kind: String = "Type Mismatch" - val explanation: String = "" + lazy val msg: String = em"Type argument ${tpe} does not conform to $which bound $bound${err.whyNoMatchStr(tpe, bound)}" + lazy val explanation: String = "" } case class DoesNotConformToSelfType(category: String, selfType: Type, cls: Symbol, otherSelf: Type, relation: String, other: Symbol)( implicit ctx: Context) extends Message(DoesNotConformToSelfTypeID) { - val msg: String = em"""$category: self type $selfType of $cls does not conform to self type $otherSelf - |of $relation $other""" val kind: String = "Type Mismatch" - val explanation: String = + lazy val msg: String = em"""$category: self type $selfType of $cls does not conform to self type $otherSelf + |of $relation $other""" + lazy val explanation: String = em"""You mixed in $other which requires self type $otherSelf, but $cls has self type |$selfType and does not inherit from $otherSelf. | @@ -1502,9 +1481,9 @@ object messages { case class DoesNotConformToSelfTypeCantBeInstantiated(tp: Type, selfType: Type)( implicit ctx: Context) extends Message(DoesNotConformToSelfTypeCantBeInstantiatedID) { - val msg: String = em"""$tp does not conform to its self type $selfType; cannot be instantiated""" val kind: String = "Type Mismatch" - val explanation: String = + lazy val msg: String = em"""$tp does not conform to its self type $selfType; cannot be instantiated""" + lazy val explanation: String = em"""To create an instance of $tp it needs to inherit $selfType in some way. | |Note: Self types are indicated with the notation @@ -1515,76 +1494,76 @@ object messages { case class AbstractMemberMayNotHaveModifier(sym: Symbol, flag: FlagSet)( implicit ctx: Context) extends Message(AbstractMemberMayNotHaveModifierID) { - val msg: String = em"""${hl("abstract")} $sym may not have `${flag.flagsString}` modifier""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""${hl("abstract")} $sym may not have `${flag.flagsString}` modifier""" + lazy val explanation: String = "" } case class TopLevelCantBeImplicit(sym: Symbol)( implicit ctx: Context) extends Message(TopLevelCantBeImplicitID) { - val msg: String = em"""${hl("implicit")} modifier cannot be used for top-level definitions""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for top-level definitions""" + lazy val explanation: String = "" } case class TypesAndTraitsCantBeImplicit()(implicit ctx: Context) extends Message(TypesAndTraitsCantBeImplicitID) { - val msg: String = em"""${hl("implicit")} modifier cannot be used for types or traits""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for types or traits""" + lazy val explanation: String = "" } case class OnlyClassesCanBeAbstract(sym: Symbol)( implicit ctx: Context) extends Message(OnlyClassesCanBeAbstractID) { - val msg: String = em"""${hl("abstract")} modifier can be used only for classes; it should be omitted for abstract members""" val kind: String = "Syntax" - val explanation: String = "" + lazy val explanation: String = "" + lazy val msg: String = em"""${hl("abstract")} modifier can be used only for classes; it should be omitted for abstract members""" } case class AbstractOverrideOnlyInTraits(sym: Symbol)( implicit ctx: Context) extends Message(AbstractOverrideOnlyInTraitsID) { - val msg: String = em"""${hl("abstract override")} modifier only allowed for members of traits""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""${hl("abstract override")} modifier only allowed for members of traits""" + lazy val explanation: String = "" } case class TraitsMayNotBeFinal(sym: Symbol)( implicit ctx: Context) extends Message(TraitsMayNotBeFinalID) { - val msg: String = em"""$sym may not be ${hl("final")}""" val kind: String = "Syntax" - val explanation: String = + lazy val msg: String = em"""$sym may not be ${hl("final")}""" + lazy val explanation: String = "A trait can never be final since it is abstract and must be extended to be useful." } case class NativeMembersMayNotHaveImplementation(sym: Symbol)( implicit ctx: Context) extends Message(NativeMembersMayNotHaveImplementationID) { - val msg: String = em"""${hl("@native")} members may not have an implementation""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""${hl("@native")} members may not have an implementation""" + lazy val explanation: String = "" } case class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( implicit ctx: Context) extends Message(OnlyClassesCanHaveDeclaredButUndefinedMembersID) { + val kind: String = "Syntax" - private val varNote = + private def varNote = if (sym.is(Mutable)) "Note that variables need to be initialized to be defined." else "" - val msg: String = em"""Declaration of $sym not allowed here: only classes can have declared but undefined members""" - val kind: String = "Syntax" - val explanation: String = s"$varNote" + lazy val msg: String = em"""Declaration of $sym not allowed here: only classes can have declared but undefined members""" + lazy val explanation: String = s"$varNote" } case class CannotExtendAnyVal(sym: Symbol)(implicit ctx: Context) extends Message(CannotExtendAnyValID) { - val msg: String = em"""$sym cannot extend ${hl("AnyVal")}""" val kind: String = "Syntax" - val explanation: String = + lazy val msg: String = em"""$sym cannot extend ${hl("AnyVal")}""" + lazy val explanation: String = em"""Only classes (not traits) are allowed to extend ${hl("AnyVal")}, but traits may extend |${hl("Any")} to become ${Green("\"universal traits\"")} which may only have ${hl("def")} members. |Universal traits can be mixed into classes that extend ${hl("AnyVal")}. @@ -1602,9 +1581,9 @@ object messages { |""".stripMargin } - val msg: String = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage + lazy val explanation: String = "" } object CannotHaveSameNameAs { sealed trait Reason @@ -1614,101 +1593,101 @@ object messages { case class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotDefineInnerID) { - val msg: String = em"""Value classes may not define an inner class""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Value classes may not define an inner class""" + lazy val explanation: String = "" } case class ValueClassesMayNotDefineNonParameterField(valueClass: Symbol, field: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotDefineNonParameterFieldID) { - val msg: String = em"""Value classes may not define non-parameter field""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Value classes may not define non-parameter field""" + lazy val explanation: String = "" } case class ValueClassesMayNotDefineASecondaryConstructor(valueClass: Symbol, constructor: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotDefineASecondaryConstructorID) { - val msg: String = em"""Value classes may not define a secondary constructor""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Value classes may not define a secondary constructor""" + lazy val explanation: String = "" } case class ValueClassesMayNotContainInitalization(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotContainInitalizationID) { - val msg: String = em"""Value classes may not contain initialization statements""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Value classes may not contain initialization statements""" + lazy val explanation: String = "" } case class ValueClassesMayNotBeAbstract(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotBeAbstractID) { - val msg: String = em"""Value classes may not be ${hl("abstract")}""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Value classes may not be ${hl("abstract")}""" + lazy val explanation: String = "" } case class ValueClassesMayNotBeContainted(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotBeContaintedID) { - private val localOrMember = if (valueClass.owner.isTerm) "local class" else "member of another class" - val msg: String = s"""Value classes may not be a $localOrMember""" val kind: String = "Syntax" - val explanation: String = "" + private def localOrMember = if (valueClass.owner.isTerm) "local class" else "member of another class" + lazy val msg: String = s"""Value classes may not be a $localOrMember""" + lazy val explanation: String = "" } case class ValueClassesMayNotWrapItself(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotWrapItselfID) { - val msg: String = """A value class may not wrap itself""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = """A value class may not wrap itself""" + lazy val explanation: String = "" } case class ValueClassParameterMayNotBeAVar(valueClass: Symbol, param: Symbol)(implicit ctx: Context) extends Message(ValueClassParameterMayNotBeAVarID) { - val msg: String = em"""A value class parameter may not be a ${hl("var")}""" val kind: String = "Syntax" - val explanation: String = + lazy val msg: String = em"""A value class parameter may not be a ${hl("var")}""" + lazy val explanation: String = em"""A value class must have exactly one ${hl("val")} parameter.""" } case class ValueClassNeedsOneValParam(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassNeedsExactlyOneValParamID) { - val msg: String = em"""Value class needs one ${hl("val")} parameter""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Value class needs one ${hl("val")} parameter""" + lazy val explanation: String = "" } case class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(implicit ctx: Context) extends Message(ValueClassParameterMayNotBeCallByNameID) { - val msg: String = s"Value class parameter `${param.name}` may not be call-by-name" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = s"Value class parameter `${param.name}` may not be call-by-name" + lazy val explanation: String = "" } case class OnlyCaseClassOrCaseObjectAllowed()(implicit ctx: Context) extends Message(OnlyCaseClassOrCaseObjectAllowedID) { - val msg: String = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" val kind: String = "Syntax" - val explanation: String = "" + lazy val msg: String = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" + lazy val explanation: String = "" } case class ExpectedToplevelDef()(implicit ctx: Context) extends Message(ExpectedTopLevelDefID) { val kind: String = "Syntax" - val msg: String = "Expected a toplevel definition" - val explanation: String = "" + lazy val msg: String = "Expected a toplevel definition" + lazy val explanation: String = "" } case class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context) extends Message(SuperCallsNotAllowedInlineableID) { val kind: String = "Syntax" - val msg: String = em"Super call not allowed in inlineable $symbol" - val explanation: String = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." + lazy val msg: String = em"Super call not allowed in inlineable $symbol" + lazy val explanation: String = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." } case class NotAPath(tp: Type, usage: String)(using Context) extends Message(NotAPathID): val kind: String = "Type" - val msg: String = em"$tp is not a valid $usage, since it is not an immutable path" - val explanation: String = + lazy val msg: String = em"$tp is not a valid $usage, since it is not an immutable path" + lazy val explanation: String = i"""An immutable path is | - a reference to an immutable value, or | - a reference to `this`, or @@ -1717,31 +1696,31 @@ object messages { case class WrongNumberOfParameters(expected: Int)(implicit ctx: Context) extends Message(WrongNumberOfParametersID) { val kind: String = "Syntax" - val msg: String = s"Wrong number of parameters, expected: $expected" - val explanation: String = "" + lazy val msg: String = s"Wrong number of parameters, expected: $expected" + lazy val explanation: String = "" } case class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) extends Message(DuplicatePrivateProtectedQualifierID) { val kind: String = "Syntax" - val msg: String = "Duplicate private/protected qualifier" - val explanation: String = + lazy val msg: String = "Duplicate private/protected qualifier" + lazy val explanation: String = em"It is not allowed to combine `private` and `protected` modifiers even if they are qualified to different scopes" } case class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) extends Message(ExpectedStartOfTopLevelDefinitionID) { val kind: String = "Syntax" - val msg: String = "Expected start of definition" - val explanation: String = + lazy val msg: String = "Expected start of definition" + lazy val explanation: String = em"You have to provide either ${hl("class")}, ${hl("trait")}, ${hl("object")}, or ${hl("enum")} definitions after qualifiers" } case class NoReturnFromInlineable(owner: Symbol)(implicit ctx: Context) extends Message(NoReturnFromInlineableID) { val kind: String = "Syntax" - val msg: String = em"No explicit ${hl("return")} allowed from inlineable $owner" - val explanation: String = + lazy val msg: String = em"No explicit ${hl("return")} allowed from inlineable $owner" + lazy val explanation: String = em"""Methods marked with ${hl("inline")} modifier may not use ${hl("return")} statements. |Instead, you should rely on the last expression's value being |returned from a method. @@ -1751,8 +1730,8 @@ object messages { case class ReturnOutsideMethodDefinition(owner: Symbol)(implicit ctx: Context) extends Message(ReturnOutsideMethodDefinitionID) { val kind: String = "Syntax" - val msg: String = em"${hl("return")} outside method definition" - val explanation: String = + lazy val msg: String = em"${hl("return")} outside method definition" + lazy val explanation: String = em"""You used ${hl("return")} in ${owner}. |${hl("return")} is a keyword and may only be used within method declarations. |""" @@ -1761,17 +1740,17 @@ object messages { case class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) extends Message(ExtendFinalClassID) { val kind: String = "Syntax" - val msg: String = em"$clazz cannot extend ${hl("final")} $finalClazz" - val explanation: String = + lazy val msg: String = em"$clazz cannot extend ${hl("final")} $finalClazz" + lazy val explanation: String = em"""A class marked with the ${hl("final")} keyword cannot be extended""" } case class ExpectedTypeBoundOrEquals(found: Token)(implicit ctx: Context) extends Message(ExpectedTypeBoundOrEqualsID) { val kind: String = "Syntax" - val msg: String = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" + lazy val msg: String = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" - val explanation: String = + lazy val explanation: String = em"""Type parameters and abstract types may be constrained by a type bound. |Such type bounds limit the concrete values of the type variables and possibly |reveal more information about the members of such types. @@ -1787,8 +1766,8 @@ object messages { case class ClassAndCompanionNameClash(cls: Symbol, other: Symbol)(implicit ctx: Context) extends Message(ClassAndCompanionNameClashID) { val kind: String = "Naming" - val msg: String = em"Name clash: both ${cls.owner} and its companion object defines ${cls.name.stripModuleClassSuffix}" - val explanation: String = + lazy val msg: String = em"Name clash: both ${cls.owner} and its companion object defines ${cls.name.stripModuleClassSuffix}" + lazy val explanation: String = em"""|A ${cls.kindString} and its companion object cannot both define a ${hl("class")}, ${hl("trait")} or ${hl("object")} with the same name: | - ${cls.owner} defines ${cls} | - ${other.owner} defines ${other}""" @@ -1797,7 +1776,7 @@ object messages { case class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) extends Message(TailrecNotApplicableID) { val kind: String = "Syntax" - val msg: String = { + lazy val msg: String = { val reason = if (!symbol.is(Method)) em"$symbol isn't a method" else if (symbol.is(Deferred)) em"$symbol is abstract" @@ -1806,14 +1785,14 @@ object messages { s"TailRec optimisation not applicable, $reason" } - val explanation: String = "" + lazy val explanation: String = "" } case class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol])(implicit ctx: Context) extends Message(FailureToEliminateExistentialID) { val kind: String = "Compatibility" - val msg: String = "Failure to eliminate existential type. Proceed at own risk." - val explanation: String = { + lazy val msg: String = "Failure to eliminate existential type. Proceed at own risk." + lazy val explanation: String = { val originalType = ctx.printer.dclsText(boundSyms, "; ").show em"""original type : $tp forSome ${originalType} |reduces to : $tp1 @@ -1824,8 +1803,8 @@ object messages { case class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(implicit ctx: Context) extends Message(OnlyFunctionsCanBeFollowedByUnderscoreID) { val kind: String = "Syntax" - val msg: String = em"Only function types can be followed by ${hl("_")} but the current expression has type $tp" - val explanation: String = + lazy val msg: String = em"Only function types can be followed by ${hl("_")} but the current expression has type $tp" + lazy val explanation: String = em"""The syntax ${hl("x _")} is no longer supported if ${hl("x")} is not a function. |To convert to a function value, you need to explicitly write ${hl("() => x")}""" } @@ -1833,8 +1812,8 @@ object messages { case class MissingEmptyArgumentList(method: Symbol)(implicit ctx: Context) extends Message(MissingEmptyArgumentListID) { val kind: String = "Syntax" - val msg: String = em"$method must be called with ${hl("()")} argument" - val explanation: String = { + lazy val msg: String = em"$method must be called with ${hl("()")} argument" + lazy val explanation: String = { val codeExample = """def next(): T = ... |next // is expanded to next()""" @@ -1851,30 +1830,30 @@ object messages { case class DuplicateNamedTypeParameter(name: Name)(implicit ctx: Context) extends Message(DuplicateNamedTypeParameterID) { val kind: String = "Syntax" - val msg: String = em"Type parameter $name was defined multiple times." - val explanation: String = "" + lazy val msg: String = em"Type parameter $name was defined multiple times." + lazy val explanation: String = "" } case class UndefinedNamedTypeParameter(undefinedName: Name, definedNames: List[Name])(implicit ctx: Context) extends Message(UndefinedNamedTypeParameterID) { val kind: String = "Syntax" - val msg: String = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." - val explanation: String = "" + lazy val msg: String = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." + lazy val explanation: String = "" } case class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends Message(IllegalStartOfStatementID) { val kind: String = "Syntax" - val msg: String = { + lazy val msg: String = { val addendum = if (isModifier) ": no modifiers allowed here" else "" "Illegal start of statement" + addendum } - val explanation: String = "A statement is either an import, a definition or an expression." + lazy val explanation: String = "A statement is either an import, a definition or an expression." } case class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends Message(TraitIsExpectedID) { val kind: String = "Syntax" - val msg: String = em"$symbol is not a trait" - val explanation: String = { + lazy val msg: String = em"$symbol is not a trait" + lazy val explanation: String = { val errorCodeExample = """class A |class B @@ -1901,18 +1880,18 @@ object messages { case class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends Message(TraitRedefinedFinalMethodFromAnyRefID) { val kind: String = "Syntax" - val msg: String = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." - val explanation: String = "" + lazy val msg: String = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." + lazy val explanation: String = "" } case class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends Message(PackageNameAlreadyDefinedID) { - val (where, or) = + val kind: String = "Naming" + lazy val (where, or) = if pkg.associatedFile == null then ("", "") else (s" in ${pkg.associatedFile}", " or delete the containing class file") - val msg: String = em"""${pkg.name} is the name of $pkg$where. + lazy val msg: String = em"""${pkg.name} is the name of $pkg$where. |It cannot be used at the same time as the name of a package.""" - val kind: String = "Naming" - val explanation: String = + lazy val explanation: String = em"""An ${hl("object")} or other toplevel definition cannot have the same name as an existing ${hl("package")}. |Rename either one of them$or.""" } @@ -1920,8 +1899,8 @@ object messages { case class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) extends Message(UnapplyInvalidNumberOfArgumentsID) { val kind: String = "Syntax" - val msg: String = em"Wrong number of argument patterns for $qual; expected: ($argTypes%, %)" - val explanation: String = + lazy val msg: String = em"Wrong number of argument patterns for $qual; expected: ($argTypes%, %)" + lazy val explanation: String = em"""The Unapply method of $qual was used with incorrect number of arguments. |Expected usage would be something like: |case $qual(${argTypes.map(_ => '_')}%, %) => ... @@ -1933,12 +1912,13 @@ object messages { case class UnapplyInvalidReturnType(unapplyResult: Type, unapplyName: Symbol#ThisName)(implicit ctx: Context) extends Message(UnapplyInvalidReturnTypeID) { val kind = "Type Mismatch" - val addendum = - if (ctx.scala2CompatMode && unapplyName == nme.unapplySeq) - "\nYou might want to try to rewrite the extractor to use `unapply` instead." - else "" - val msg = em"""| ${Red(i"$unapplyResult")} is not a valid result type of an $unapplyName method of an ${Magenta("extractor")}.$addendum""" - val explanation = if (unapplyName.show == "unapply") + lazy val msg = + val addendum = + if (ctx.scala2CompatMode && unapplyName == nme.unapplySeq) + "\nYou might want to try to rewrite the extractor to use `unapply` instead." + else "" + em"""| ${Red(i"$unapplyResult")} is not a valid result type of an $unapplyName method of an ${Magenta("extractor")}.$addendum""" + lazy val explanation = if (unapplyName.show == "unapply") em""" |To be used as an extractor, an unapply method has to return a type that either: | - has members ${Magenta("isEmpty: Boolean")} and ${Magenta("get: S")} (usually an ${Green("Option[S]")}) @@ -1986,17 +1966,16 @@ object messages { } case class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends Message(StaticFieldsOnlyAllowedInObjectsID) { - val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}." val kind: String = "Syntax" - val explanation: String = + lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}." + lazy val explanation: String = em"${hl("@static")} members are only allowed inside objects." } case class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends Message(StaticFieldsShouldPrecedeNonStaticID) { - val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined before non-static fields." val kind: String = "Syntax" - - val explanation: String = { + lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined before non-static fields." + lazy val explanation: String = { val nonStatics = defns.takeWhile(_.symbol != member).take(3).filter(_.isInstanceOf[tpd.ValDef]) val codeExample = s"""object ${member.owner.name.firstPart} { | @static ${member} = ... @@ -2016,8 +1995,8 @@ object messages { case class CyclicInheritance(symbol: Symbol, addendum: String)(implicit ctx: Context) extends Message(CyclicInheritanceID) { val kind: String = "Syntax" - val msg: String = em"Cyclic inheritance: $symbol extends itself$addendum" - val explanation: String = { + lazy val msg: String = em"Cyclic inheritance: $symbol extends itself$addendum" + lazy val explanation: String = { val codeExample = "class A extends A" em"""Cyclic inheritance is prohibited in Dotty. @@ -2034,7 +2013,7 @@ object messages { case class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) extends Message(BadSymbolicReferenceID) { val kind: String = "Reference" - val msg: String = { + lazy val msg: String = { val denotationOwner = denot.owner val denotationName = ctx.fresh.setSetting(ctx.settings.YdebugNames, true).printer.nameString(denot.name) val file = denot.symbol.associatedFile @@ -2048,20 +2027,20 @@ object messages { |the classpath might be incompatible with the version used when compiling $src.""" } - val explanation: String = "" + lazy val explanation: String = "" } case class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends Message(UnableToExtendSealedClassID) { val kind: String = "Syntax" - val msg: String = em"Cannot extend ${hl("sealed")} $pclazz in a different source file" - val explanation: String = "A sealed class or trait can only be extended in the same file as its declaration" + lazy val msg: String = em"Cannot extend ${hl("sealed")} $pclazz in a different source file" + lazy val explanation: String = "A sealed class or trait can only be extended in the same file as its declaration" } case class SymbolHasUnparsableVersionNumber(symbol: Symbol, migrationMessage: String)(implicit ctx: Context) extends Message(SymbolHasUnparsableVersionNumberID) { val kind: String = "Syntax" - val msg: String = em"${symbol.showLocated} has an unparsable version number: $migrationMessage" - val explanation: String = + lazy val msg: String = em"${symbol.showLocated} has an unparsable version number: $migrationMessage" + lazy val explanation: String = em"""$migrationMessage | |The ${symbol.showLocated} is marked with ${hl("@migration")} indicating it has changed semantics @@ -2074,8 +2053,8 @@ object messages { migrationVersion: ScalaVersion )(implicit ctx: Context) extends Message(SymbolChangedSemanticsInVersionID) { val kind: String = "Syntax" - val msg: String = em"${symbol.showLocated} has changed semantics in version $migrationVersion" - val explanation: String = { + lazy val msg: String = em"${symbol.showLocated} has changed semantics in version $migrationVersion" + lazy val explanation: String = { em"""The ${symbol.showLocated} is marked with ${hl("@migration")} indicating it has changed semantics |between versions and the ${hl("-Xmigration")} settings is used to warn about constructs |whose behavior may have changed since version change.""" @@ -2085,9 +2064,9 @@ object messages { case class UnableToEmitSwitch(tooFewCases: Boolean)(implicit ctx: Context) extends Message(UnableToEmitSwitchID) { val kind: String = "Syntax" - val tooFewStr: String = if (tooFewCases) " since there are not enough cases" else "" - val msg: String = em"Could not emit switch for ${hl("@switch")} annotated match$tooFewStr" - val explanation: String = { + def tooFewStr: String = if (tooFewCases) " since there are not enough cases" else "" + lazy val msg: String = em"Could not emit switch for ${hl("@switch")} annotated match$tooFewStr" + lazy val explanation: String = { val codeExample = """val ConstantB = 'B' |final val ConstantC = 'C' @@ -2113,17 +2092,17 @@ object messages { } case class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) extends Message(MissingCompanionForStaticID) { - val msg: String = em"${member.owner} does not have a companion class" val kind: String = "Syntax" - val explanation: String = + lazy val msg: String = em"${member.owner} does not have a companion class" + lazy val explanation: String = em"An object that contains ${hl("@static")} members must have a companion class." } case class PolymorphicMethodMissingTypeInParent(rsym: Symbol, parentSym: Symbol)(implicit ctx: Context) extends Message(PolymorphicMethodMissingTypeInParentID) { val kind: String = "Syntax" - val msg: String = em"Polymorphic refinement $rsym without matching type in parent $parentSym is no longer allowed" - val explanation: String = + lazy val msg: String = em"Polymorphic refinement $rsym without matching type in parent $parentSym is no longer allowed" + lazy val explanation: String = em"""Polymorphic $rsym is not allowed in the structural refinement of $parentSym because |$rsym does not override any method in $parentSym. Structural refinement does not allow for |polymorphic methods.""" @@ -2132,25 +2111,25 @@ object messages { case class ParamsNoInline(owner: Symbol)(implicit ctx: Context) extends Message(ParamsNoInlineID) { val kind: String = "Syntax" - val msg: String = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" - val explanation: String = "" + lazy val msg: String = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" + lazy val explanation: String = "" } case class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends Message(JavaSymbolIsNotAValueID) { val kind: String = "Type Mismatch" - val msg: String = { + lazy val msg: String = { val kind = if (symbol is Package) em"$symbol" else em"Java defined ${hl("class " + symbol.name)}" s"$kind is not a value" } - val explanation: String = "" + lazy val explanation: String = "" } case class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends Message(DoubleDefinitionID) { val kind: String = "Duplicate Symbol" - val msg: String = { + lazy val msg: String = { def nameAnd = if (decl.name != previousDecl.name) " name and" else "" def details(implicit ctx: Context): String = if (decl.isRealMethod && previousDecl.isRealMethod) { @@ -2191,47 +2170,47 @@ object messages { |${decl.showDcl} ${symLocation(decl)} |""" + details } - val explanation: String = "" + lazy val explanation: String = "" } case class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends Message(ImportRenamedTwiceID) { val kind: String = "Syntax" - val msg: String = s"${ident.show} is renamed twice on the same import line." - val explanation: String = "" + lazy val msg: String = s"${ident.show} is renamed twice on the same import line." + lazy val explanation: String = "" } case class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends Message(TypeTestAlwaysSucceedsID) { val kind: String = "Syntax" - val msg: String = { + lazy val msg: String = { val addendum = if (foundCls != testCls) s" is a subtype of $testCls" else " is the same as the tested type" s"The highlighted type test will always succeed since the scrutinee type ($foundCls)" + addendum } - val explanation: String = "" + lazy val explanation: String = "" } // Relative of CyclicReferenceInvolvingImplicit and RecursiveValueNeedsResultType case class TermMemberNeedsResultTypeForImplicitSearch(cycleSym: Symbol)(implicit ctx: Context) extends Message(TermMemberNeedsNeedsResultTypeForImplicitSearchID) { val kind: String = "Cyclic" - val msg: String = em"""$cycleSym needs result type because its right-hand side attempts implicit search""" - val explanation: String = + lazy val msg: String = em"""$cycleSym needs result type because its right-hand side attempts implicit search""" + lazy val explanation: String = em"""|The right hand-side of $cycleSym's definition requires an implicit search at the highlighted position. |To avoid this error, give `$cycleSym` an explicit type. |""".stripMargin } case class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends Message(ClassCannotExtendEnumID) { - override def kind: String = "Syntax" - override def msg: String = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" - override def explanation: String = "" + val kind: String = "Syntax" + lazy val msg: String = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" + lazy val explanation: String = "" } case class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends Message(NotAnExtractorID) { - override def msg: String = em"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method" - override def kind: String = "Syntax" - override def explanation: String = + val kind: String = "Syntax" + lazy val msg: String = em"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method" + lazy val explanation: String = em"""|An ${hl("unapply")} method should be defined in an ${hl("object")} as follow: | - If it is just a test, return a ${hl("Boolean")}. For example ${hl("case even()")} | - If it returns a single sub-value of type T, return an ${hl("Option[T]")} @@ -2244,74 +2223,72 @@ object messages { case class MemberWithSameNameAsStatic()(implicit val ctx: Context) extends Message(MemberWithSameNameAsStaticID) { - - override def msg: String = em"Companion classes cannot define members with same name as a ${hl("@static")} member" - override def kind: String = "Syntax" - override def explanation: String = "" + val kind: String = "Syntax" + lazy val msg: String = em"Companion classes cannot define members with same name as a ${hl("@static")} member" + lazy val explanation: String = "" } case class PureExpressionInStatementPosition(stat: untpd.Tree, exprOwner: Symbol)(implicit ctx: Context) extends Message(PureExpressionInStatementPositionID) { - val kind = "Potential Issue" - val msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" - val explanation = + lazy val msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" + lazy val explanation = em"""The pure expression $stat doesn't have any side effect and its result is not assigned elsewhere. |It can be removed without changing the semantics of the program. This may indicate an error.""".stripMargin } case class TraitCompanionWithMutableStatic()(implicit val ctx: Context) extends Message(TraitCompanionWithMutableStaticID) { - override def msg: String = em"Companion of traits cannot define mutable @static fields" - override def kind: String = "Syntax" - override def explanation: String = "" + val kind: String = "Syntax" + lazy val msg: String = em"Companion of traits cannot define mutable @static fields" + lazy val explanation: String = "" } case class LazyStaticField()(implicit val ctx: Context) extends Message(LazyStaticFieldID) { - override def msg: String = em"Lazy @static fields are not supported" - override def kind: String = "Syntax" - override def explanation: String = "" + val kind: String = "Syntax" + lazy val msg: String = em"Lazy @static fields are not supported" + lazy val explanation: String = "" } case class StaticOverridingNonStaticMembers()(implicit val ctx: Context) extends Message(StaticOverridingNonStaticMembersID) { - override def msg: String = em"${hl("@static")} members cannot override or implement non-static ones" - override def kind: String = "Syntax" - override def explanation: String = "" + val kind: String = "Syntax" + lazy val msg: String = em"${hl("@static")} members cannot override or implement non-static ones" + lazy val explanation: String = "" } case class OverloadInRefinement(rsym: Symbol)(implicit val ctx: Context) extends Message(OverloadInRefinementID) { - override def msg: String = "Refinements cannot introduce overloaded definitions" - override def kind: String = "Overload" - override def explanation: String = - em"""The refinement `$rsym` introduces an overloaded definition. - |Refinements cannot contain overloaded definitions.""".stripMargin - } + val kind: String = "Overload" + lazy val msg: String = "Refinements cannot introduce overloaded definitions" + lazy val explanation: String = + em"""The refinement `$rsym` introduces an overloaded definition. + |Refinements cannot contain overloaded definitions.""".stripMargin + } case class NoMatchingOverload(alternatives: List[SingleDenotation], pt: Type)( err: Errors)(implicit val ctx: Context) extends Message(NoMatchingOverloadID) { - val msg: String = + val kind: String = "Type Mismatch" + lazy val msg: String = em"""None of the ${err.overloadedAltsStr(alternatives)} |match ${err.expectedTypeStr(pt)}""" - val kind: String = "Type Mismatch" - val explanation: String = "" + lazy val explanation: String = "" } case class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) extends Message(StableIdentPatternID) { - override def kind: String = "Type" - override def msg: String = + val kind: String = "Type" + lazy val msg: String = em"""Stable identifier required, but $tree found""" - override def explanation: String = "" + lazy val explanation: String = "" } case class IllegalSuperAccessor(base: Symbol, memberName: Name, acc: Symbol, accTp: Type, other: Symbol, otherTp: Type)(implicit val ctx: Context) extends Message(IllegalSuperAccessorID) { val kind: String = "Reference" - val msg: String = { + lazy val msg: String = { // The mixin containing a super-call that requires a super-accessor val accMixin = acc.owner // The class or trait that the super-accessor should resolve too in `base` @@ -2360,15 +2337,15 @@ object messages { | super-call to a specific parent, e.g. $staticSuperCall |""".stripMargin } - val explanation: String = "" + lazy val explanation: String = "" } case class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) extends Message(TraitParameterUsedAsParentPrefixID) { val kind: String = "Reference" - val msg: String = + lazy val msg: String = s"${cls.show} cannot extend from a parent that is derived via its own parameters" - val explanation: String = + lazy val explanation: String = ex""" |The parent class/trait that ${cls.show} extends from is obtained from |the parameter of ${cls.show}. This is disallowed in order to prevent @@ -2382,9 +2359,9 @@ object messages { case class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) extends Message(UnknownNamedEnclosingClassOrObjectID) { val kind: String = "Reference" - val msg: String = + lazy val msg: String = em"""no enclosing class or object is named '${hl(name.show)}'""" - val explanation: String = + lazy val explanation: String = ex""" |The class or object named '${hl(name.show)}' was used as a visibility |modifier, but could not be resolved. Make sure that @@ -2396,24 +2373,24 @@ object messages { case class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context) extends Message(IllegalCyclicTypeReferenceID) { val kind: String = "Cyclic" - val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" - val explanation: String = "" + lazy val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" + lazy val explanation: String = "" } case class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) extends Message(ErasedTypesCanOnlyBeFunctionTypesID) { val kind: String = "Syntax" - val msg: String = "Types with erased keyword can only be function types `(erased ...) => ...`" - val explanation: String = "" + lazy val msg: String = "Types with erased keyword can only be function types `(erased ...) => ...`" + lazy val explanation: String = "" } case class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(CaseClassMissingNonImplicitParamListID) { val kind: String = "Syntax" - val msg: String = + lazy val msg: String = em"""|A ${hl("case class")} must have at least one non-implicit parameter list""" - val explanation: String = + lazy val explanation: String = em"""|${cdef.name} must have at least one non-implicit parameter list, | if you're aiming to have a case class parametrized only by implicit ones, you should | add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""".stripMargin @@ -2422,9 +2399,9 @@ object messages { case class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(EnumerationsShouldNotBeEmptyID) { val kind: String = "Syntax" - val msg: String = "Enumerations must contain at least one case" + lazy val msg: String = "Enumerations must contain at least one case" - val explanation: String = + lazy val explanation: String = em"""|Enumeration ${cdef.name} must contain at least one case |Example Usage: | ${hl("enum")} ${cdef.name} { @@ -2436,9 +2413,9 @@ object messages { case class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context) extends Message(AbstractCannotBeUsedForObjectsID) { val kind: String = "Syntax" - val msg: String = em"${hl("abstract")} modifier cannot be used for objects" + lazy val msg: String = em"${hl("abstract")} modifier cannot be used for objects" - val explanation: String = + lazy val explanation: String = em"""|Objects are final and cannot be extended, thus cannot have the ${hl("abstract")} modifier | |You may want to define an abstract class: @@ -2452,9 +2429,9 @@ object messages { case class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context) extends Message(ModifierRedundantForObjectsID) { val kind: String = "Syntax" - val msg: String = em"${hl(modifier)} modifier is redundant for objects" + lazy val msg: String = em"${hl(modifier)} modifier is redundant for objects" - val explanation: String = + lazy val explanation: String = em"""|Objects cannot be extended making the ${hl(modifier)} modifier redundant. |You may want to define the object without it: | ${hl("object")} ${mdef.name} { } @@ -2464,9 +2441,9 @@ object messages { case class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) extends Message(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { val kind: String = "Syntax" - val msg: String = i"explicit extends clause needed because both enum case and enum class have type parameters" + lazy val msg: String = i"explicit extends clause needed because both enum case and enum class have type parameters" - val explanation: String = + lazy val explanation: String = em"""Enumerations where the enum class as well as the enum case have type parameters need |an explicit extends. |for example: @@ -2479,9 +2456,9 @@ object messages { case class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) extends Message(IllegalRedefinitionOfStandardKindID) { val kind: String = "Syntax" - val msg: String = em"illegal redefinition of standard $kindType $name" + lazy val msg: String = em"illegal redefinition of standard $kindType $name" - val explanation: String = + lazy val explanation: String = em"""| "$name" is a standard Scala core `$kindType` | Please choose a different name to avoid conflicts |""".stripMargin @@ -2490,9 +2467,9 @@ object messages { case class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) extends Message(NoExtensionMethodAllowedID) { val kind: String = "Syntax" - val msg: String = em"No extension method allowed here, since collective parameters are given" + lazy val msg: String = em"No extension method allowed here, since collective parameters are given" - val explanation: String = + lazy val explanation: String = em"""|Extension method: | `${mdef}` |is defined inside an extension clause which has collective parameters. @@ -2502,9 +2479,9 @@ object messages { case class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) extends Message(ExtensionMethodCannotHaveTypeParamsID) { val kind: String = "Syntax" - val msg: String = i"Extension method cannot have type parameters since some were already given previously" + lazy val msg: String = i"Extension method cannot have type parameters since some were already given previously" - val explanation: String = + lazy val explanation: String = em"""|Extension method: | `${mdef}` |has type parameters `[${mdef.tparams.map(_.show).mkString(",")}]`, while the extension clause has @@ -2515,9 +2492,9 @@ object messages { case class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) extends Message(ExtensionCanOnlyHaveDefsID) { val kind: String = "Syntax" - val msg: String = em"Only methods allowed here, since collective parameters are given" + lazy val msg: String = em"Only methods allowed here, since collective parameters are given" - val explanation: String = + lazy val explanation: String = em"""Extension clauses can only have `def`s | `${mdef.show}` is not a valid expression here. |""".stripMargin @@ -2526,9 +2503,9 @@ object messages { case class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) extends Message(UnexpectedPatternForSummonFromID) { val kind: String = "Syntax" - val msg: String = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" + lazy val msg: String = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" - val explanation: String = + lazy val explanation: String = em"""|The pattern "${tree.show}" provided in the ${hl("case")} expression of the ${hl("summonFrom")}, | needs to be of the form ${hl("`x: T`")} or ${hl("`_`")}. | @@ -2547,9 +2524,9 @@ object messages { case class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) extends Message(AnonymousInstanceCannotBeEmptyID) { val kind: String = "Syntax" - val msg: String = i"anonymous instance must implement a type or have at least one extension method" + lazy val msg: String = i"anonymous instance must implement a type or have at least one extension method" - val explanation: String = + lazy val explanation: String = em"""|Anonymous instances cannot be defined with an empty body. The block |`${impl.show}` should either contain an implemented type or at least one extension method. |""".stripMargin @@ -2558,9 +2535,9 @@ object messages { case class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) extends Message(TypeSpliceInValPatternID) { val kind: String = "Syntax" - val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead." + lazy val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead." - val explanation: String = + lazy val explanation: String = em"""|Type splice: `$$${expr.show}` cannot be used in a `val` pattern. Consider rewriting the `val` pattern |as a `match` with a corresponding `case` to replace the `val`. |""".stripMargin @@ -2569,8 +2546,8 @@ object messages { case class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) extends Message(ModifierNotAllowedForDefinitionID) { val kind: String = "Syntax" - val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition" + lazy val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition" - val explanation: String = "" + lazy val explanation: String = "" } } From 2a783625dc98c080e4612da41496e07935c53a7a Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Tue, 24 Mar 2020 20:21:38 +0100 Subject: [PATCH 02/13] Make sure not to pass expensive arguments to message constructors Also: - Turn some message classes into normal classes. More to follow. For error messages there's really no justification to spend all the extra code size on case class infrastructure. - Drop ErrorMessageTest. That's the only test that requires message classes to be case classes. Over the whole time of its existence, that test was nothing more than a pain in the ass. I do not think there was a single real fault that it reported but it caused lots of extra work everytime a message changes. Best not to waste more cycles composing and fixing these tests. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- .../dotc/reporting/diagnostic/messages.scala | 90 +- .../tools/dotc/transform/TreeChecker.scala | 3 +- .../dotty/tools/dotc/typer/Applications.scala | 12 +- .../tools/dotc/typer/ErrorReporting.scala | 40 +- .../dotty/tools/dotc/typer/RefChecks.scala | 2 +- .../dotc/reporting/ErrorMessagesTests.scala | 1862 ----------------- .../dotc/reporting/TestMessageLaziness.scala | 4 +- 8 files changed, 72 insertions(+), 1943 deletions(-) delete mode 100644 compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 91fe8f06daad..f84f50aa8a68 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -981,7 +981,7 @@ object desugar { var name = mdef.name if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName(impl)) if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) { - def kind = if (name.isTypeName) "class" else "object" + val kind = if (name.isTypeName) "class" else "object" ctx.error(IllegalRedefinitionOfStandardKind(kind, name), mdef.sourcePos) name = name.errorName } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 5decb781f070..73209060df0b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -3,27 +3,23 @@ package dotc package reporting package diagnostic -import dotc.core._ +import core._ import Contexts.Context -import Decorators._ -import Symbols._ -import Names._ -import NameOps._ -import Types._ +import Decorators._, Symbols._, Names._, NameOps._, Types._, Flags._ +import Denotations.SingleDenotation +import SymDenotations.SymDenotation import util.SourcePosition import config.Settings.Setting import interfaces.Diagnostic.{ERROR, INFO, WARNING} -import dotc.parsing.Scanners.Token -import dotc.parsing.Tokens +import parsing.Scanners.Token +import parsing.Tokens import printing.Highlighting._ import printing.Formatting import ErrorMessageID._ -import Denotations.SingleDenotation -import dotty.tools.dotc.ast.Trees -import dotty.tools.dotc.config.ScalaVersion -import dotty.tools.dotc.core.Flags._ -import dotty.tools.dotc.core.SymDenotations.SymDenotation -import dotty.tools.dotc.typer.ErrorReporting.Errors +import ast.Trees +import config.ScalaVersion +import typer.ErrorReporting.{Errors, err} +import typer.ProtoTypes.ViewProto import scala.util.control.NonFatal import StdNames.nme import printing.Formatting.hl @@ -277,7 +273,7 @@ object messages { } } - case class MissingIdent(tree: untpd.Ident, treeKind: String, name: Name)(implicit ctx: Context) + class MissingIdent(tree: untpd.Ident, treeKind: String, val name: Name)(implicit ctx: Context) extends Message(MissingIdentID) { val kind: String = "Unbound Identifier" lazy val msg: String = em"Not found: $treeKind$name" @@ -290,21 +286,54 @@ object messages { } } - case class TypeMismatch(found: Type, expected: Type, whyNoMatch: String = "", implicitFailure: String = "")(implicit ctx: Context) - extends Message(TypeMismatchID) { + class TypeMismatch(found: Type, expected: Type, addendum: => String = "")(implicit ctx: Context) + extends Message(TypeMismatchID): val kind: String = "Type Mismatch" - lazy val msg: String = { - val (where, printCtx) = Formatting.disambiguateTypes(found, expected) + + // replace constrained TypeParamRefs and their typevars by their bounds where possible + // the idea is that if the bounds are also not-subtypes of each other to report + // the type mismatch on the bounds instead of the original TypeParamRefs, since + // these are usually easier to analyze. + object reported extends TypeMap: + def setVariance(v: Int) = variance = v + val constraint = ctx.typerState.constraint + def apply(tp: Type): Type = tp match + case tp: TypeParamRef => + constraint.entry(tp) match + case bounds: TypeBounds => + if variance < 0 then apply(ctx.typeComparer.fullUpperBound(tp)) + else if variance > 0 then apply(ctx.typeComparer.fullLowerBound(tp)) + else tp + case NoType => tp + case instType => apply(instType) + case tp: TypeVar => apply(tp.stripTypeVar) + case _ => mapOver(tp) + + lazy val msg: String = + val found1 = reported(found) + reported.setVariance(-1) + val expected1 = reported(expected) + val (found2, expected2) = + if (found1 frozen_<:< expected1) (found, expected) else (found1, expected1) + val postScript = + if !addendum.isEmpty + || expected.isAny + || expected.isAnyRef + || expected.isRef(defn.AnyValClass) + || defn.isBottomType(found) + then addendum + else ctx.typer.importSuggestionAddendum(ViewProto(found.widen, expected)) + val (where, printCtx) = Formatting.disambiguateTypes(found2, expected2) val whereSuffix = if (where.isEmpty) where else s"\n\n$where" - val (fnd, exp) = Formatting.typeDiff(found, expected)(printCtx) - s"""|Found: $fnd - |Required: $exp""".stripMargin + whereSuffix + whyNoMatch + implicitFailure - } + val (foundStr, expectedStr) = Formatting.typeDiff(found2, expected2)(printCtx) + s"""|Found: $foundStr + |Required: $expectedStr""".stripMargin + + whereSuffix + err.whyNoMatchStr(found, expected) + postScript lazy val explanation: String = "" - } + end TypeMismatch - case class NotAMember(site: Type, name: Name, selected: String, addendum: String = "")(implicit ctx: Context) + class NotAMember(site: Type, val name: Name, selected: String, addendum: => String = "")(implicit ctx: Context) extends Message(NotAMemberID) { val kind: String = "Member Not Found" @@ -843,9 +872,10 @@ object messages { |""" } - case class PatternMatchExhaustivity(uncovered: String)(implicit ctx: Context) + class PatternMatchExhaustivity(uncoveredFn: => String)(implicit ctx: Context) extends Message(PatternMatchExhaustivityID) { val kind: String = "Pattern Match Exhaustivity" + lazy val uncovered = uncoveredFn lazy val msg: String = em"""|${hl("match")} may not be exhaustive. | @@ -860,10 +890,10 @@ object messages { |""" } - case class UncheckedTypePattern(msg: String)(implicit ctx: Context) + class UncheckedTypePattern(msgFn: => String)(implicit ctx: Context) extends Message(UncheckedTypePatternID) { val kind: String = "Pattern Match Exhaustivity" - + lazy val msg = msgFn lazy val explanation: String = em"""|Type arguments and type refinements are erased during compile time, thus it's |impossible to check them at run-time. @@ -1993,7 +2023,7 @@ object messages { } } - case class CyclicInheritance(symbol: Symbol, addendum: String)(implicit ctx: Context) extends Message(CyclicInheritanceID) { + class CyclicInheritance(symbol: Symbol, addendum: => String)(implicit ctx: Context) extends Message(CyclicInheritanceID) { val kind: String = "Syntax" lazy val msg: String = em"Cyclic inheritance: $symbol extends itself$addendum" lazy val explanation: String = { @@ -2036,7 +2066,7 @@ object messages { lazy val explanation: String = "A sealed class or trait can only be extended in the same file as its declaration" } - case class SymbolHasUnparsableVersionNumber(symbol: Symbol, migrationMessage: String)(implicit ctx: Context) + class SymbolHasUnparsableVersionNumber(symbol: Symbol, migrationMessage: => String)(implicit ctx: Context) extends Message(SymbolHasUnparsableVersionNumberID) { val kind: String = "Syntax" lazy val msg: String = em"${symbol.showLocated} has an unparsable version number: $migrationMessage" diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 29c0b6a8398d..9ec747f41669 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -16,6 +16,7 @@ import core.Mode import typer._ import typer.ErrorReporting._ import reporting.ThrowingReporter +import reporting.diagnostic.messages.TypeMismatch import ast.Trees._ import ast.{tpd, untpd} import scala.internal.Chars._ @@ -517,7 +518,7 @@ class TreeChecker extends Phase with SymTransformer { !isPrimaryConstructorReturn && !pt.isInstanceOf[FunOrPolyProto]) assert(tree.tpe <:< pt, { - val mismatch = err.typeMismatchMsg(tree.tpe, pt) + val mismatch = TypeMismatch(tree.tpe, pt) i"""|${mismatch.msg} |found: ${infoStr(tree.tpe)} |expected: ${infoStr(pt)} diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index bf59407708a8..51497410991e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -29,7 +29,7 @@ import config.Printers.{overload, typr, unapp} import TypeApplications._ import reporting.diagnostic.Message -import reporting.diagnostic.messages.{UnexpectedPatternForSummonFrom, NotAMember, MissingIdent} +import reporting.diagnostic.messages.{UnexpectedPatternForSummonFrom, NotAMember, MissingIdent, TypeMismatch} import reporting.trace import Constants.{Constant, IntTag, LongTag} import dotty.tools.dotc.reporting.diagnostic.messages.{UnapplyInvalidReturnType, NotAnExtractor, UnapplyInvalidNumberOfArguments} @@ -349,7 +349,7 @@ trait Applications extends Compatibility { // it might be healed by an implicit conversion () else - fail(err.typeMismatchMsg(methType.resultType, resultType)) + fail(TypeMismatch(methType.resultType, resultType)) // match all arguments with corresponding formal parameters matchArgs(orderedArgs, methType.paramInfos, 0) @@ -1069,10 +1069,10 @@ trait Applications extends Compatibility { state.reporter.pendingMessages match case msg :: Nil => msg.contained match - case NotAMember(_, name, _, _) => - memberName.isEmpty || name == memberName - case MissingIdent(_, _, name) => - memberName.isEmpty || name == memberName + case msg: NotAMember => + memberName.isEmpty || msg.name == memberName + case msg: MissingIdent => + memberName.isEmpty || msg.name == memberName case _ => false case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 86b4f862acfc..268100b12d1a 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -98,7 +98,7 @@ object ErrorReporting { val normTp = normalize(tree.tpe, pt) val treeTp = if (normTp <:< pt) tree.tpe else normTp // use normalized type if that also shows an error, original type otherwise - errorTree(tree, typeMismatchMsg(treeTp, pt, implicitFailure.whyNoConversion)) + errorTree(tree, TypeMismatch(treeTp, pt, implicitFailure.whyNoConversion)) } /** A subtype log explaining why `found` does not conform to `expected` */ @@ -123,44 +123,6 @@ object ErrorReporting { "" } - def typeMismatchMsg(found: Type, expected: Type, postScript: String = ""): TypeMismatch = { - // replace constrained TypeParamRefs and their typevars by their bounds where possible - // the idea is that if the bounds are also not-subtypes of each other to report - // the type mismatch on the bounds instead of the original TypeParamRefs, since - // these are usually easier to analyze. - object reported extends TypeMap { - def setVariance(v: Int) = variance = v - val constraint = ctx.typerState.constraint - def apply(tp: Type): Type = tp match { - case tp: TypeParamRef => - constraint.entry(tp) match { - case bounds: TypeBounds => - if (variance < 0) apply(ctx.typeComparer.fullUpperBound(tp)) - else if (variance > 0) apply(ctx.typeComparer.fullLowerBound(tp)) - else tp - case NoType => tp - case instType => apply(instType) - } - case tp: TypeVar => apply(tp.stripTypeVar) - case _ => mapOver(tp) - } - } - val found1 = reported(found) - reported.setVariance(-1) - val expected1 = reported(expected) - val (found2, expected2) = - if (found1 frozen_<:< expected1) (found, expected) else (found1, expected1) - val postScript1 = - if !postScript.isEmpty - || expected.isAny - || expected.isAnyRef - || expected.isRef(defn.AnyValClass) - || defn.isBottomType(found) - then postScript - else ctx.typer.importSuggestionAddendum(ViewProto(found.widen, expected)) - TypeMismatch(found2, expected2, whyNoMatchStr(found, expected), postScript1) - } - /** Format `raw` implicitNotFound or implicitAmbiguous argument, replacing * all occurrences of `${X}` where `X` is in `paramNames` with the * corresponding shown type in `args`. diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index c5a476df1328..091461980ab2 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -231,7 +231,7 @@ object RefChecks { infoStringWithLocation(other), infoStringWithLocation(member)) else if (ctx.settings.Ydebug.value) - err.typeMismatchMsg(memberTp(self), otherTp(self)) + TypeMismatch(memberTp(self), otherTp(self)) else "" "error overriding %s;\n %s %s%s".format( diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala deleted file mode 100644 index f5c280ae290e..000000000000 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ /dev/null @@ -1,1862 +0,0 @@ -package dotty.tools -package dotc -package reporting - -import dotty.tools.backend.jvm.GenBCode -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.Types.WildcardType -import dotty.tools.dotc.parsing.Tokens -import dotty.tools.dotc.reporting.diagnostic.messages._ -import dotty.tools.dotc.transform.{CheckStatic, Erasure, PostTyper, TailRec} -import dotty.tools.dotc.typer.{FrontEnd, RefChecks} -import org.junit.Assert._ -import org.junit.Test - -class ErrorMessagesTests extends ErrorMessagesTest { - // In the case where there are no errors, we can do "expectNoErrors" in the - // `Report` - @Test def noErrors = - checkMessagesAfter(FrontEnd.name)("""class Foo""") - .expectNoErrors - - @Test def caseClassExtendsEnum = - checkMessagesAfter(RefChecks.name) { - """ - |enum Foo { case A, B } - |case class Bar() extends Foo - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head - val ClassCannotExtendEnum(cls, parent) :: Nil = messages - assertEquals("Bar", cls.name.show) - assertEquals("Foo", parent.name.show) - assertEquals("", cls.owner.name.show) - } - - @Test def typeMismatch = - checkMessagesAfter(FrontEnd.name) { - """ - |object Foo { - | def bar: String = 1 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - val defn = ictx.definitions - - // Assert that we only got one error message - assertMessageCount(1, messages) - - // Pattern match out the expected error - val TypeMismatch(found, expected, _, _) :: Nil = messages - - // The type of the right hand side will actually be the constant 1, - // therefore we check if it "derivesFrom" `IntClass` - assert(found.derivesFrom(defn.IntClass), s"found was: $found") - - // The expected type is `scala.String` which we dealias to - // `java.lang.String` and compare with `=:=` to `defn.StringType` which - // is a type reference to `java.lang.String` - assert(expected.dealias =:= defn.StringType, s"expected was: $expected") - } - - @Test def overridesNothing = - checkMessagesAfter(RefChecks.name) { - """ - |object Foo { - | override def bar: Unit = {} - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverridesNothing(member) :: Nil = messages - assertEquals("bar", member.name.show) - } - - @Test def overridesNothingDifferentSignature = - checkMessagesAfter(RefChecks.name) { - """ - |class Bar { - | def bar(s: String): Unit = {} - | def bar(s: Int): Unit = {} - | final def bar(s: Long): Unit = {} - |} - |object Foo extends Bar { - | override def bar: Unit = {} - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverridesNothingButNameExists(member, sameName) :: Nil = messages - // check expected context data - assertEquals("bar", member.name.show) - assertEquals(3, sameName.size) - assert(sameName.forall(_.symbol.name.show == "bar"), - "at least one method had an unexpected name") - } - - @Test def forwardReference = - checkMessagesAfter(RefChecks.name) { - """ - |object Forward { - | def block = { - | a.toInt - | val b = 2 - | val a = BigDecimal("4") - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ForwardReferenceExtendsOverDefinition(value, definition) :: Nil = messages - assertEquals("value b", value.show) - assertEquals("value a", definition.show) - } - - @Test def unexpectedToken = - checkMessagesAfter(FrontEnd.name) { - """ - |object Forward { - | def val = "ds" - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ExpectedTokenButFound(expected, found) :: Nil = messages - assertEquals(Tokens.IDENTIFIER, expected) - assertEquals(Tokens.VAL, found) - } - - @Test def expectedToken = - checkMessagesAfter(FrontEnd.name) { - """ - |object Forward { - | def `val` = "ds" - |} - """.stripMargin - } - .expectNoErrors - - @Test def leftAndRightAssociative = - checkMessagesAfter(FrontEnd.name) { - """ - |object Ops { - | case class I(j: Int) { - | def +-(i: Int) = i - | def +:(i: Int) = i - | } - | val v = I(1) +- I(4) +: I(4) - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc) :: Nil = messages - assertEquals("+-", op1.show) - assertEquals("+:", op2.show) - assertFalse(op2LeftAssoc) - } - - @Test def cantInstantiateAbstract = - checkMessagesAfter(RefChecks.name) { - """ - |object Scope { - | abstract class Concept - | val x = new Concept() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages - assertEquals("Concept", cls.name.show) - assertFalse("expected class", isTrait) - } - - @Test def cantInstantiateTrait = - checkMessagesAfter(RefChecks.name) { - """ - |object Scope { - | trait Concept - | val x = new Concept() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages - assertEquals("Concept", cls.name.show) - assertTrue("expected trait", isTrait) - } - - @Test def overloadedMethodNeedsReturnType = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | def foo(i: Int) = foo(i.toString) - | def foo(s: String) = s - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("foo", cycleSym.name.show) - } - - @Test def i1731 = - checkMessagesAfter(FrontEnd.name) { - """ - |case class Foo[T](x: T) - |object Foo { def apply[T]() = Foo(null.asInstanceOf[T]) } - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("apply", cycleSym.name.show) - } - - @Test def recursiveMethodNeedsReturnType = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | def i = i + 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("i", cycleSym.name.show) - } - - @Test def recursiveValueNeedsReturnType = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | lazy val i = i + 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val RecursiveValueNeedsResultType(cycleSym) :: Nil = messages - assertEquals("i", cycleSym.name.show) - } - - @Test def recursiveValueNeedsReturnType2 = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | lazy val i = j + 5 - | lazy val j = i - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val RecursiveValueNeedsResultType(cycleSym) :: Nil = messages - assertEquals("i", cycleSym.name.show) - } - - @Test def cyclicReferenceInvolving = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | val x: T = ??? - | type T <: x.type // error: cyclic reference involving value x - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CyclicReferenceInvolving(denot) :: Nil = messages - assertEquals("value x", denot.show) - } - - @Test def cyclicReferenceInvolving2 = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | implicit val x: T = ??? - | type T <: x.type // error: cyclic reference involving value x - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CyclicReferenceInvolving(denot) :: Nil = messages - assertEquals("value x", denot.show) - } - - @Test def mutualRecursionre_i2001 = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def odd(x: Int) = if (x == 0) false else !even(x-1) - | def even(x: Int) = if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("odd", cycleSym.name.show) - } - - @Test def mutualRecursion_i2001a = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def odd(x: Int) = if (x == 0) false else !even(x-1) - | def even(x: Int) = { - | def foo = { - | if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type - | } - | false - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("odd", cycleSym.name.show) - } - - @Test def mutualRecursion_i2001b = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def odd(x: Int) = if (x == 0) false else !even(x-1) - | def even(x: Int) = { - | val foo = { - | if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type - | } - | false - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("odd", cycleSym.name.show) - } - - @Test def termMemberNeedsResultTypeForImplicitSearch = - checkMessagesAfter(FrontEnd.name) { - """ - |object implicitDefs { - | def foo(implicit x: String) = 1 - | def bar() = { - | implicit val x = foo - | x - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages - assertEquals("x", cycleSym.name.show) - } - - @Test def implicitSearchForcesImplicitRetType_i4709 = - checkMessagesAfter(FrontEnd.name) { - """ - |import scala.language.implicitConversions - | - |class Context - |class ContextBase { def settings = 1 } - | - |class Test { - | implicit def toBase(ctx: Context): ContextBase = ??? - | - | def test(ctx0: Context) = { - | implicit val ctx = { ctx0.settings; ??? } - | } - |} - """.stripMargin - } - .expect{ (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages - assertEquals("ctx", cycleSym.name.show) - } - - @Test def implicitSearchForcesNonImplicitRetTypeOnExplicitImport_i3253 = - checkMessagesAfter(FrontEnd.name) { - """ - |import Test.test - | - |object Test { - | def test = " " * 10 - |} - """.stripMargin - } - .expect{ (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages - assertEquals("test", cycleSym.name.show) - } - - @Test def superQualMustBeParent = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def foo(): Unit = () - |} - | - |class B { - |} - | - |class C extends A { - | super[B].foo - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val SuperQualMustBeParent(qual, cls) :: Nil = messages - - assertEquals("B", qual.show) - assertEquals("class C", cls.show) - } - - @Test def ambiguousImport = - checkMessagesAfter(FrontEnd.name) { - """ - |object A { - | class ToBeImported - |} - |object B { - | class ToBeImported - |} - |class C { - | import A.ToBeImported - | import B.ToBeImported - | - | val value: ToBeImported = ??? - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - import typer.Typer.BindingPrec._ - - assertMessageCount(1, messages) - val AmbiguousImport(name, newPrec, prevPrec, prevCtx) :: Nil = messages - assertEquals("ToBeImported", name.show) - assertEquals(NamedImport, newPrec) - assertEquals(NamedImport, prevPrec) - } - - @Test def methodDoesNotTakeParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |object Scope { - | def foo = () - | foo() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val msg @ MethodDoesNotTakeParameters(tree) = messages.head - - assertEquals("Scope.foo", tree.show) - assertEquals("method foo", msg.methodSymbol.show) - } - - @Test def methodDoesNotTakeMoreParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |object Scope{ - | def foo(a: Int) = () - | foo(1)("2") - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val msg @ MethodDoesNotTakeParameters(tree) = messages.head - - assertEquals("Scope.foo(1)", tree.show) - assertEquals("method foo", msg.methodSymbol.show) - } - - @Test def ambiugousOverloadWithWildcard = - checkMessagesAfter(FrontEnd.name) { - """object Context { - | trait A { - | def foo(s: String): String - | def foo: String = foo("foo") - | } - | object B extends A { - | def foo(s: String): String = s - | } - | B.foo - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val AmbiguousOverload(tree, List(alt1, alt2), pt: WildcardType) :: Nil = messages - assertEquals("method foo", alt1.show) - assertEquals("(s: String): String", alt1.info.show) - assertEquals("method foo", alt2.show) - } - - @Test def reassignmentToVal = - checkMessagesAfter(FrontEnd.name) { - """ - |class Context { - | val value = 3 - | value = 4 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ReassignmentToVal(name) :: Nil = messages - assertEquals("value", name.show) - } - - @Test def typeDoesNotTakeParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |trait WithOutParams - |class Extending extends WithOutParams[String] - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TypeDoesNotTakeParameters(tpe, params) :: Nil = messages - assertEquals("WithOutParams", tpe.show) - } - - @Test def parameterizedTypeLacksParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |trait WithParams(s: String) - |class Extending extends WithParams - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ParameterizedTypeLacksArguments(symbol) :: Nil = messages - assertEquals("trait WithParams", symbol.show) - } - - @Test def varValParametersMayNotBeCallByName = - checkMessagesAfter(FrontEnd.name) { - "trait Trait(val noNoNo: => String)" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val VarValParametersMayNotBeCallByName(name, false) :: Nil = messages - assertEquals("noNoNo", name.show) - } - - @Test def missingTypeParameter = - checkMessagesAfter(FrontEnd.name) { - """object Scope { - | val value: List = null - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val MissingTypeParameterFor(tpe) :: Nil = messages - assertEquals("List", tpe.show) - } - - @Test def missingTypeParameterInTypeApp = - checkMessagesAfter(RefChecks.name) { - """object Scope { - | def f[T] = ??? - | val x = f[List] - | val y = f[Either] - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(2, messages) - assertEquals("Missing type parameter for List", messages(1).msg) - assertEquals("Missing type parameters for Either", messages(0).msg) - } - - @Test def doesNotConformToBound = - checkMessagesAfter(RefChecks.name) { - """class WithParam[A <: List[Int]] - |object Scope { - | val value: WithParam[Int] = null - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoesNotConformToBound(tpe, which, bound) :: Nil = messages - assertEquals("Int", tpe.show) - assertEquals("upper", which) - assertEquals("List[Int]", bound.show) - } - - @Test def doesNotConformToSelfType = - checkMessagesAfter(RefChecks.name) { - """class Base - |trait BlendItIn { - | this: Base => - |} - |class Blended extends BlendItIn - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoesNotConformToSelfType(category, selfType, cls, otherSelf, relation, other) :: Nil = messages - assertEquals("illegal inheritance", category) - assertEquals("Blended", selfType.show) - assertEquals("class Blended", cls.show) - assertEquals("Base", otherSelf.show) - assertEquals("parent", relation) - assertEquals("trait BlendItIn", other.show) - } - - @Test def doesNotConformToSelfTypeCantBeInstantiated = - checkMessagesAfter(RefChecks.name) { - """class Base - |class RequiresBase { self: Base => } - |object Scope { - | val x = new RequiresBase - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoesNotConformToSelfTypeCantBeInstantiated(tpe, selfType) :: Nil = messages - assertEquals("RequiresBase", tpe.show) - assertEquals("Base", selfType.show) - } - - @Test def abstractValueMayNotHaveFinalModifier = - checkMessagesAfter(FrontEnd.name) { - """abstract class Foo { - | final val s: String - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val AbstractMemberMayNotHaveModifier(symbol, flags) :: Nil = messages - assertEquals("value s", symbol.show) - assertEquals("final", flags.flagsString) - } - - @Test def typesAndTraitsCantBeImplicit = - checkMessagesAfter(FrontEnd.name) { - """class Foo { - | implicit trait S - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val TypesAndTraitsCantBeImplicit() :: Nil = messages - } - - @Test def onlyClassesCanBeAbstract = - checkMessagesAfter(FrontEnd.name) { - """class Foo { - | abstract val s: String - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val OnlyClassesCanBeAbstract(symbol) :: Nil = messages - assertEquals("value s", symbol.show) - } - - @Test def abstractOverrideOnlyInTraits = - checkMessagesAfter(FrontEnd.name) { - """class Foo { - | abstract override val s: String = "" - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val AbstractOverrideOnlyInTraits(symbol) :: Nil = messages - assertEquals("value s", symbol.show) - } - - @Test def traitMayNotBeFinal = - checkMessagesAfter(FrontEnd.name) { - """final trait Foo""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val TraitsMayNotBeFinal(symbol) :: Nil = messages - assertEquals("trait Foo", symbol.show) - } - - @Test def nativeMemberMayNotHaveImplementation = - checkMessagesAfter(FrontEnd.name) { - """trait Foo { - | @native def foo() = 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val NativeMembersMayNotHaveImplementation(symbol) :: Nil = messages - assertEquals("method foo", symbol.show) - } - - @Test def onlyClassesCanHaveDeclaredButUndefinedMembers = - checkMessagesAfter(FrontEnd.name) { - """object Foo { - | def foo(): Int - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val OnlyClassesCanHaveDeclaredButUndefinedMembers(symbol) :: Nil = messages - assertEquals("method foo", symbol.show) - } - - @Test def cannotExtendAnyval = - checkMessagesAfter(FrontEnd.name) { - """trait Foo extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CannotExtendAnyVal(symbol) :: Nil = messages - assertEquals("trait Foo", symbol.show) - } - - @Test def cannotHaveSameNameAs = - checkMessagesAfter(RefChecks.name) { - """trait Foo { - | class A - |} - |class B extends Foo { - | class A - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CannotHaveSameNameAs(symbol, cls, _) :: Nil = messages - assertEquals("class A", symbol.show) - assertEquals("class A", cls.show) - } - - @Test def valueClassesMayNotDefineInner = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | class Inner - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotDefineInner(valueClass, inner) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("class Inner", inner.show) - } - - @Test def valueClassesMayNotDefineNonParameterField = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | val illegal: Int - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotDefineNonParameterField(valueClass, field) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("value illegal", field.show) - } - - @Test def valueClassesMayNotDefineASecondaryConstructor = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | def this() = this(2) - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotDefineASecondaryConstructor(valueClass, constuctor) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("constructor MyValue", constuctor.show) - } - - @Test def valueClassesMayNotContainInitalization = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | println("Hallo?") - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotContainInitalization(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassesMayNotBeContained = - checkMessagesAfter(RefChecks.name) { - """class Outer { - | class MyValue(i: Int) extends AnyVal - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotBeContainted(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassesMayNotWrapItself = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: MyValue) extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotWrapItself(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassParameterMayNotBeVar = - checkMessagesAfter(RefChecks.name) { - """class MyValue(var i: Int) extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassParameterMayNotBeAVar(valueClass, param) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("variable i", param.show) - } - - @Test def valueClassNeedsOneVal = - checkMessagesAfter(RefChecks.name) { - """class MyValue() extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassNeedsOneValParam(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassParameterMayNotBeCallByName = - checkMessagesAfter(RefChecks.name) { - """class MyValue(a: => Int) extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassParameterMayNotBeCallByName(valueClass, param) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("value a", param.show) - } - - @Test def onlyCaseClassOrCaseObjectAllowed = - checkMessagesAfter(FrontEnd.name) { - """case Foobar""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val err :: Nil = messages - assertEquals(err, OnlyCaseClassOrCaseObjectAllowed()) - } - - @Test def expectedClassOrObjectDef = - checkMessagesAfter(FrontEnd.name) { - """Foo""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val err :: Nil = messages - assertEquals(err, ExpectedToplevelDef()) - } - - @Test def implicitClassPrimaryConstructorArity = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | implicit class Foo(i: Int, s: String) - |} - """.stripMargin - } - .expect { (itcx, messages) => - implicit val ctx: Context = itcx - assertMessageCount(1, messages) - val err :: Nil = messages - assertEquals(err, ImplicitClassPrimaryConstructorArity()) - } - - @Test def superCallsNotAllowedInline = - checkMessagesAfter(RefChecks.name) { - """ - |class A { - | def foo(): Unit = () - |} - | - |class B extends A { - | inline def bar(): Unit = super.foo() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val err :: Nil = messages - val SuperCallsNotAllowedInlineable(symbol) = err - assertEquals("method bar", symbol.show) - } - - @Test def wildcardOnTypeArgumentNotAllowedOnNew = - checkMessagesAfter(RefChecks.name) { - """ - |object TyperDemo { - | class Team[A] - | val team = new Team[?] - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(err, WildcardOnTypeArgumentNotAllowedOnNew()) - } - - @Test def wrongNumberOfParameters = - checkMessagesAfter(RefChecks.name) { - """object NumberOfParams { - | def unary[T](x: T => Unit) = () - | unary((x, y) => ()) - |} """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(err, WrongNumberOfParameters(1)) - } - - @Test def duplicatePrivateProtectedQualifier = - checkMessagesAfter(FrontEnd.name) { - """class Test { - | private[Test] protected[this] def foo(): Unit = () - |} """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(DuplicatePrivateProtectedQualifier(), err) - } - - @Test def expectedStartOfTopLevelDefinition = - checkMessagesAfter(FrontEnd.name) { - """private Test {}""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(ExpectedStartOfTopLevelDefinition(), err) - } - - @Test def missingReturnTypeWithReturnStatement = - checkMessagesAfter(FrontEnd.name) { - """class BadFunction { - | def bad() = { return "fail" } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - - val MissingReturnTypeWithReturnStatement(method) :: Nil = messages - assertEquals(method.name.show, "bad") - } - - @Test def noReturnInInline = - checkMessagesAfter(FrontEnd.name) { - """class BadFunction { - | inline def usesReturn: Int = { return 42 } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - - val NoReturnFromInlineable(method) :: Nil = messages - assertEquals("method usesReturn", method.show) - } - - @Test def returnOutsideMethodDefinition = - checkMessagesAfter(FrontEnd.name) { - """object A { - | return 5 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ReturnOutsideMethodDefinition(owner) :: Nil = messages - assertEquals("object A", owner.show) - } - - @Test def extendFinalClass = checkMessagesAfter(RefChecks.name) { - """final class A - | - |class B extends A - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ExtendFinalClass(extender, parent) :: Nil = messages - assertEquals(extender.show, "class B") - assertEquals(parent.show, "class A") - } - - @Test def tailrecNotApplicableNeitherPrivateNorFinal = - checkMessagesAfter(TailRec.name) { - """ - |class Foo { - | @scala.annotation.tailrec - | def foo: Unit = foo - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val TailrecNotApplicable(method) :: Nil = messages - assertEquals(method.show, "method foo") - } - - @Test def expectedTypeBoundOrEquals = - checkMessagesAfter(FrontEnd.name) { - """object typedef { - | type asd > Seq - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ExpectedTypeBoundOrEquals(found) :: Nil = messages - assertEquals(Tokens.IDENTIFIER, found) - } - - @Test def classAndCompanionNameClash = - checkMessagesAfter(RefChecks.name) { - """ - |class T { - | class G - |} - |object T { - | trait G - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ClassAndCompanionNameClash(cls, other) :: Nil = messages - - assertEquals("class T", cls.owner.show) - assertEquals("class G", cls.show) - assertEquals("object T", other.owner.show) - assertEquals("trait G", other.show) - - } - - @Test def onlyFunctionsCanBeFollowedByUnderscore = - checkMessagesAfter(FrontEnd.name) { - """ - |class T { - | def main(args: Array[String]): Unit = { - | val n = "T" - | val func = n _ - | } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OnlyFunctionsCanBeFollowedByUnderscore(tp) :: Nil = messages - assertEquals("String", tp.show) - } - - @Test def missingEmptyArgumentList = - checkMessagesAfter(FrontEnd.name) { - """ - |class Test { - | def greet(): String = "Hello" - | def main(args: Array[String]): Unit = { - | greet - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val MissingEmptyArgumentList(method) :: Nil = messages - assertEquals("method greet", method.show) - } - - @Test def duplicateNamedTypeParameter = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | def f[A, B]() = ??? - | f[A=Any, A=Any]() - | f[B=Any, B=Any]() - |} - | - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(2, messages) - val DuplicateNamedTypeParameter(n2) :: DuplicateNamedTypeParameter(n1) :: Nil = messages - assertEquals("A", n1.show) - assertEquals("B", n2.show) - } - - @Test def undefinedNamedTypeParameter = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | def f[A, B]() = ??? - | f[A=Any, C=Any]() - | f[C=Any, B=Any]() - |} - | - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(2, messages) - val UndefinedNamedTypeParameter(n2, l2) :: UndefinedNamedTypeParameter(n1, l1) :: Nil = messages - val tpParams = List("A", "B") - assertEquals("C", n1.show) - assertEquals(tpParams, l1.map(_.show)) - assertEquals("C", n2.show) - assertEquals(tpParams, l2.map(_.show)) - - } - - @Test def illegalStartOfStatement = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | { with } - | { private ) } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(2, messages) - val errWithModifier :: err :: Nil = messages - - assertEquals(IllegalStartOfStatement(isModifier = false), err) - assertEquals(IllegalStartOfStatement(isModifier = true), errWithModifier) - } - - @Test def traitIsExpected = - checkMessagesAfter(FrontEnd.name) { - """ - |class A - |class B - | - |object Test { - | def main(args: Array[String]): Unit = { - | val a = new A with B - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TraitIsExpected(symbol) :: Nil = messages - assertEquals("class B", symbol.show) - } - - @Test def traitRedefinedFinalMethodFromAnyRef = - checkMessagesAfter(RefChecks.name) { - """ - |trait C { - | def wait (): Unit - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TraitRedefinedFinalMethodFromAnyRef(method) = messages.head - assertEquals("method wait", method.show) - } - - @Test def packageNameAlreadyDefined = - checkMessagesAfter(FrontEnd.name) { - """ - |package bar { } - |object bar { } - | - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - val PackageNameAlreadyDefined(pkg) = messages.head - assertEquals(pkg.show, "object bar") - } - - @Test def unapplyInvalidNumberOfArguments = - checkMessagesAfter(FrontEnd.name) { - """ - |case class Boo(a: Int, b: String) - | - |object autoTuplingNeg2 { - | val z = Boo(1, "foo") - | - | z match { - | case Boo(a, b, c) => a - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnapplyInvalidNumberOfArguments(qual, argTypes) :: Nil = messages - assertEquals("Boo", qual.show) - assertEquals("(class Int, type String)", argTypes.map(_.typeSymbol).mkString("(", ", ", ")")) - } - - @Test def unapplyInvalidReturnType = - checkMessagesAfter("typer") { - """ - |class A(val i: Int) - | - |object A { - | def unapply(a: A): Int = a.i - | def test(a: A) = a match { - | case A() => 1 - | } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnapplyInvalidReturnType(unapplyResult, unapplyName) :: Nil = messages - assertEquals("Int", unapplyResult.show) - assertEquals("unapply", unapplyName.show) - } - - @Test def unapplySeqInvalidReturnType = - checkMessagesAfter("typer") { - """ - |class A(val i: Int) - | - |object A { - | def unapplySeq(a: A): Int = a.i - | def test(a: A) = a match { - | case A() => 1 - | } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnapplyInvalidReturnType(unapplyResult, unapplyName) :: Nil = messages - assertEquals("Int", unapplyResult.show) - assertEquals("unapplySeq", unapplyName.show) - } - - @Test def staticOnlyAllowedInsideObjects = - checkMessagesAfter(CheckStatic.name) { - """ - |class Foo { - | @annotation.static def bar(): Unit = bar() - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - val StaticFieldsOnlyAllowedInObjects(field) = messages.head - assertEquals(field.show, "method bar") - } - - @Test def staticShouldPrecedeNonStatic = - checkMessagesAfter(CheckStatic.name) { - """ - |class Foo - |object Foo { - | val foo = 1 - | @annotation.static val bar = 2 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - val StaticFieldsShouldPrecedeNonStatic(field, _) = messages.head - assertEquals(field.show, "value bar") - } - - @Test def cyclicInheritance = - checkMessagesAfter(FrontEnd.name) { - "class A extends A" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CyclicInheritance(symbol, _) :: Nil = messages - assertEquals("class A", symbol.show) - } - - @Test def missingCompanionForStatic = - checkMessagesAfter(CheckStatic.name) { - """ - |object Foo { - | @annotation.static def bar(): Unit = () - |} - """.stripMargin - }.expect { (itcx, messages) => - implicit val ctx: Context = itcx - val MissingCompanionForStatic(member) = messages.head - assertEquals(member.show, "method bar") - } - - @Test def polymorphicMethodMissingTypeInParent = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | import scala.reflect.Selectable.reflectiveSelectable - | def foo(x: { def get[T](a: T): Int }) = 5 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val PolymorphicMethodMissingTypeInParent(rsym, parentSym) = messages.head - assertEquals("method get", rsym.show) - assertEquals("class Object", parentSym.show) - } - - @Test def typeDoubleDeclaration = - checkMessagesAfter(FrontEnd.name) { - """ - |class Foo { - | val a = 1 - | val a = 2 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoubleDefinition(symbol, previousSymbol, _) :: Nil = messages - assertEquals(symbol.name.mangledString, "a") - } - - @Test def renameImportTwice = - checkMessagesAfter(PostTyper.name) { - """ - |import java.lang.{Integer => Foo, Integer => Baz} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val (msg @ ImportRenamedTwice(ident)) :: Nil = messages - assertEquals(ident.show, "Integer") - } - - @Test def tailRecOptimisation = - checkMessagesAfter(FrontEnd.name) { - """ - |import scala.annotation.tailrec - |@tailrec - |object Test { - | @tailrec val a = "" - | @tailrec var b = "" - |} - |@tailrec - |class Test {} - | - """.stripMargin - }.expect{ (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(4, messages) - - val tailRecMessages = messages.map({ case TailrecNotApplicable(sym) => sym.showKind }).toSet - assertEquals(tailRecMessages, Set("variable", "value", "object", "class")) - } - - @Test def notAnExtractor() = - checkMessagesAfter(FrontEnd.name) { - """ - | trait Foo - | object Foo - | object Test { - | def test(foo: Foo) = foo match { - | case Foo(name) => ??? - | } - | } - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val NotAnExtractor(tree) = messages.head - assertEquals("Foo", tree.show) - } - - @Test def memberWithSameNameAsStatic() = - checkMessagesAfter(CheckStatic.name) { - """ - |import scala.annotation.static - |class Camp { - | val name = "" - |} - |object Camp { - | @static val name = "" - |} - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[MemberWithSameNameAsStatic]) - assertEquals(message.msg, "Companion classes cannot define members with same name as a @static member") - } - - @Test def companionOfTraitWithMutableStatic() = - checkMessagesAfter(CheckStatic.name) { - """ - | import scala.annotation.static - | trait Test - | object Test { - | @static var myStatic = "" - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[TraitCompanionWithMutableStatic]) - assertEquals( - "Companion of traits cannot define mutable @static fields", - message.msg - ) - } - - @Test def lazyStaticField() = - checkMessagesAfter(CheckStatic.name) { - """ - | import scala.annotation.static - | class Test - | object Test { - | @static lazy val myStatic = "" - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[LazyStaticField]) - assertEquals( - "Lazy @static fields are not supported", - message.msg - ) - } - - @Test def staticOverridingNonStatic() = - checkMessagesAfter(CheckStatic.name) { - """ - | import scala.annotation.static - | trait Foo { - | val foo = "" - | } - | class Test - | object Test extends Foo { - | @static val foo = "" - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[StaticOverridingNonStaticMembers]) - assertEquals( - "@static members cannot override or implement non-static ones", - message.msg - ) - } - - @Test def StableIdentifiers() = - checkMessagesAfter(FrontEnd.name) { - """ - | object Test { - | var x = 2 - | def test = 2 match { - | case `x` => x + 1 - | } - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[StableIdentPattern]) - assertEquals( - "Stable identifier required, but `x` found", - message.msg - ) - } - - @Test def traitParametersUsedAsParentPrefix() = - checkMessagesAfter(RefChecks.name) { - """ - |class Outer { - | trait Inner - | trait Test(val outer: Outer) extends outer.Inner - |} - |""".stripMargin - }.expect { - (ictx, messages) => - implicit val ctx: Context = ictx - val TraitParameterUsedAsParentPrefix(cls) :: Nil = messages - assertEquals("trait Test", cls.show) - assertEquals( - s"${cls.show} cannot extend from a parent that is derived via its own parameters", - messages.head.msg - ) - } - - @Test def unknownNamedEnclosingClassOrObject() = - checkMessagesAfter(RefChecks.name) { - """ - |class TestObject { - | private[doesNotExist] def test: Int = 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnknownNamedEnclosingClassOrObject(name) :: Nil = messages - assertEquals("doesNotExist", name.show) - } - - @Test def illegalCyclicTypeReference() = - checkMessagesAfter(RefChecks.name) { - """ - |type X = List[X] - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val IllegalCyclicTypeReference(sym, where, lastChecked) :: Nil = messages - assertEquals("type X", sym.show) - assertEquals("alias", where) - assertEquals("List[X]", lastChecked.show) - } - - @Test def erasedTypesCanOnlyBeFunctionTypesSuccess() = - checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int) => Int): Int = 1") - .expectNoErrors - - @Test def erasedTypesCanOnlyBeFunctionTypesFailed() = - checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int)): Int = 1") - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ErasedTypesCanOnlyBeFunctionTypes() :: Nil = messages - assertEquals("Types with erased keyword can only be function types `(erased ...) => ...`", messages.head.msg) - } - - @Test def caseClassMissingParamListSuccessful = - checkMessagesAfter(FrontEnd.name) ("case class Test()") - .expectNoErrors - - @Test def caseClassMissingParamListFailed = - checkMessagesAfter(FrontEnd.name) ("case class Test") - .expect { - (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CaseClassMissingParamList(tpe) :: Nil = messages - assertEquals("A case class must have at least one parameter list", messages.head.msg) - } - - @Test def caseClassMissingNonImplicitParamListSuccessful = - checkMessagesAfter(FrontEnd.name) ("case class Test()(using foo: String)") - .expectNoErrors - - @Test def caseClassMissingNonImplicitParamListFailed = - checkMessagesAfter(FrontEnd.name) ("case class Test(using foo: String)") - .expect { - (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CaseClassMissingNonImplicitParamList(tpe) :: Nil = messages - assertEquals("A case class must have at least one non-implicit parameter list", messages.head.msg) - } - - @Test def enumMustContainOneCase = - checkMessagesAfter(RefChecks.name) { - """ - |enum Foo { } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val EnumerationsShouldNotBeEmpty(typeDef) :: Nil = messages - assertEquals("Enumerations must contain at least one case", errorMsg) - assertEquals("Foo", typeDef.name.toString) - } - - @Test def objectsCannotBeAbstract = - checkMessagesAfter(RefChecks.name) { - """ - |abstract object Foo { } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val AbstractCannotBeUsedForObjects(mdef) :: Nil = messages - assertEquals("abstract modifier cannot be used for objects", errorMsg) - assertEquals("Foo", mdef.name.toString) - } - - @Test def sealedOnObjectsIsRedundant = - checkMessagesAfter(RefChecks.name) { - """ - |sealed object Foo { } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val ModifierRedundantForObjects(mdef, "sealed") :: Nil = messages - assertEquals("sealed modifier is redundant for objects", errorMsg) - assertEquals("Foo", mdef.name.toString) - } - - @Test def enumAndCaseWithTypesNeedExplicitExtends = - checkMessagesAfter(RefChecks.name) { - """ - |enum E[T,U,V] { - | case C[X,Y,Z](x: X, y: Y, z: Z) - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef, caseDef) :: Nil = messages - assertEquals("explicit extends clause needed because both enum case and enum class have type parameters", errorMsg) - assertEquals("E", enumDef.name.toString) - assertEquals("C", caseDef.name.toString) - } - - @Test def illegalRedefinitionOfStandardKind = - checkMessagesAfter(RefChecks.name) { - """ package scala { - | class Any() - | } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val IllegalRedefinitionOfStandardKind(kind, name) :: Nil = messages - assertEquals("illegal redefinition of standard class Any", errorMsg) - assertEquals("class", kind) - assertEquals("Any", name.toString) - } - - @Test def unexpectedPatternForSummonFrom = - checkMessagesAfter(RefChecks.name) { - """import compiletime.summonFrom - |inline def a = summonFrom { - | case x => ??? - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val UnexpectedPatternForSummonFrom(x) :: Nil = messages - assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) - assertEquals("x", x.show) - } - - @Test def unexpectedPatternForSummonWithPatternBinder = - checkMessagesAfter(RefChecks.name) { - """import compiletime.summonFrom - |inline def a = summonFrom { - | case x@String => ??? - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val UnexpectedPatternForSummonFrom(x) :: Nil = messages - assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) - assertEquals("given x @ String", x.show) - } - - @Test def typeSplicesInValPatterns = - checkMessagesAfter(RefChecks.name) { - s"""import scala.quoted._ - |object Foo { - | def f(using q: QuoteContext) = { - | val t: Type[Int] = ??? - | val '[ *:[$$t] ] = ??? - | } - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val TypeSpliceInValPattern(x) :: Nil = messages - assertEquals("Type splices cannot be used in val patterns. Consider using `match` instead.", errorMsg) - assertEquals("t", x.show) - } - - @Test def modifierNotAllowedForDefinition = - checkMessagesAfter(RefChecks.name) { - """object Test { - | opaque def o: Int = 3 - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val ModifierNotAllowedForDefinition(x) :: Nil = messages - assertEquals("Modifier `opaque` is not allowed for this definition", errorMsg) - assertEquals("opaque", x.flagsString) - } -} diff --git a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala index 858660075bb2..f4d68a3b9be8 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -18,10 +18,8 @@ class TestMessageLaziness extends DottyTest { } case class LazyError() extends Message(ErrorMessageID.LazyErrorId) { - throw new Error("Didn't stay lazy.") - val kind = "Test" - val msg = "Please don't blow up" + lazy val msg = throw new Error("Didn't stay lazy.") val explanation = "" } From 9897a23ab4c3cf32562a1c614f7f439943abd40f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 10:09:43 +0100 Subject: [PATCH 03/13] Make Message computations strict --- .../src/dotty/tools/dotc/core/Contexts.scala | 8 +-- .../tools/dotc/core/SymDenotations.scala | 4 +- .../src/dotty/tools/dotc/core/Types.scala | 19 +++-- .../dotty/tools/dotc/reporting/Reporter.scala | 32 ++++----- .../dotc/reporting/diagnostic/Message.scala | 69 ++++--------------- .../diagnostic/MessageContainer.scala | 10 +-- .../dotty/tools/dotc/typer/Applications.scala | 12 ++-- .../dotc/reporting/TestMessageLaziness.scala | 2 +- 8 files changed, 47 insertions(+), 109 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index 686102286668..ea9cd66d53ca 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -750,11 +750,11 @@ object Contexts { * of underlying during a controlled operation exists. */ private[core] val pendingUnderlying: mutable.HashSet[Type] = new mutable.HashSet[Type] - /** A map from ErrorType to associated message computation. We use this map - * instead of storing message computations directly in ErrorTypes in order - * to avoid space leaks - the message computation usually captures a context. + /** A map from ErrorType to associated message. We use this map + * instead of storing messages directly in ErrorTypes in order + * to avoid space leaks - the message usually captures a context. */ - private[core] val errorTypeMsg: mutable.Map[Types.ErrorType, () => Message] = mutable.Map() + private[core] val errorTypeMsg: mutable.Map[Types.ErrorType, Message] = mutable.Map() // Phases state diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index a6828bc88c6e..b1dea9afea95 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -2368,7 +2368,7 @@ object SymDenotations { /** A completer for missing references */ class StubInfo() extends LazyType { - def initializeToDefaults(denot: SymDenotation, errMsg: => Message)(implicit ctx: Context): Unit = { + def initializeToDefaults(denot: SymDenotation, errMsg: Message)(implicit ctx: Context): Unit = { denot.info = denot match { case denot: ClassDenotation => ClassInfo(denot.owner.thisType, denot.classSymbol, Nil, EmptyScope) @@ -2380,7 +2380,7 @@ object SymDenotations { def complete(denot: SymDenotation)(implicit ctx: Context): Unit = { val sym = denot.symbol - def errMsg = BadSymbolicReference(denot) + val errMsg = BadSymbolicReference(denot) ctx.error(errMsg, sym.sourcePos) if (ctx.debug) throw new scala.Error() initializeToDefaults(denot, errMsg) diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9b00c9a87392..cfebb6641bb3 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -4650,19 +4650,16 @@ object Types { def msg(implicit ctx: Context): Message } - object ErrorType { - def apply(msg: => Message)(implicit ctx: Context): ErrorType = { - val et = new ErrorType { - def msg(implicit ctx: Context): Message = - ctx.base.errorTypeMsg.get(this) match { - case Some(msgFun) => msgFun() + object ErrorType: + def apply(m: Message)(implicit ctx: Context): ErrorType = + val et = new ErrorType: + def msg(using ctx: Context): Message = + ctx.base.errorTypeMsg.get(this) match + case Some(m) => m case None => "error message from previous run no longer available" - } - } - ctx.base.errorTypeMsg(et) = () => msg + ctx.base.errorTypeMsg(et) = m et - } - } + end ErrorType object UnspecifiedErrorType extends ErrorType { override def msg(implicit ctx: Context): Message = "unspecified error" diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 2a4ca680496e..d8e19b2310ca 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -87,16 +87,16 @@ trait Reporting { this: Context => } else reporter.report(warning) - def deprecationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def deprecationWarning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = reportWarning(new DeprecationWarning(msg, pos)) - def migrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def migrationWarning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = reportWarning(new MigrationWarning(msg, pos)) - def uncheckedWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def uncheckedWarning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = reportWarning(new UncheckedWarning(msg, pos)) - def featureWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def featureWarning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = reportWarning(new FeatureWarning(msg, pos)) def featureWarning(feature: String, featureDescription: String, @@ -120,18 +120,14 @@ trait Reporting { this: Context => else reportWarning(new FeatureWarning(msg, pos)) } - def warning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def warning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = reportWarning(new Warning(msg, addInlineds(pos))) - def strictWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = { - val fullPos = addInlineds(pos) - if (this.settings.strict.value) error(msg, fullPos) - else reportWarning( - new ExtendMessage(() => msg)(_ + "\n(This would be an error under strict mode)") - .warning(fullPos)) - } + def strictWarning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = + if (this.settings.strict.value) error(msg, pos) + else warning(msg.append("\n(This would be an error under strict mode)"), pos) - def error(msg: => Message, pos: SourcePosition = NoSourcePosition, sticky: Boolean = false): Unit = { + def error(msg: Message, pos: SourcePosition = NoSourcePosition, sticky: Boolean = false): Unit = { val fullPos = addInlineds(pos) reporter.report(if (sticky) new StickyError(msg, fullPos) else new Error(msg, fullPos)) if ctx.settings.YdebugError.value then Thread.dumpStack() @@ -143,15 +139,13 @@ trait Reporting { this: Context => ex.printStackTrace } - def errorOrMigrationWarning(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = + def errorOrMigrationWarning(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = if (ctx.scala2CompatMode) migrationWarning(msg, pos) else error(msg, pos) - def restrictionError(msg: => Message, pos: SourcePosition = NoSourcePosition): Unit = - reporter.report { - new ExtendMessage(() => msg)(m => s"Implementation restriction: $m").error(addInlineds(pos)) - } + def restrictionError(msg: Message, pos: SourcePosition = NoSourcePosition): Unit = + error(msg.mapMsg("Implementation restriction: " + _), pos) - def incompleteInputError(msg: => Message, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = + def incompleteInputError(msg: Message, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = reporter.incomplete(new Error(msg, pos))(ctx) /** Log msg if settings.log contains the current phase. diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index 37a409d1246d..3fcd77ea34dc 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -56,72 +56,27 @@ abstract class Message(val errorId: ErrorMessageID) { self => def explanation: String /** The implicit `Context` in messages is a large thing that we don't want - * persisted. This method gets around that by duplicating the message - * without the implicit context being passed along. + * persisted. This method gets around that by duplicating the message, + * forcing its `msg` and `explanation` vals and dropping the implicit context + * that was captured in the original message. */ def persist: Message = new Message (errorId) { - val msg = self.msg - val kind = self.kind - val explanation = self.explanation - } - - def append(suffix: => String): Message = new Message(errorId) { - val msg = self.msg ++ suffix val kind = self.kind - val explanation = self.explanation - } - - def appendExplanation(suffix: => String): Message = new Message(errorId): val msg = self.msg - val kind = self.kind - val explanation = self.explanation ++ suffix -} - -/** An extended message keeps the contained message from being evaluated, while - * allowing for extension for the `msg` string - * - * This is useful when we need to add additional information to an existing - * message. - */ -class ExtendMessage(_msg: () => Message)(f: String => String) { self => - lazy val msg: String = f(_msg().msg) - lazy val kind: String = _msg().kind - lazy val explanation: String = _msg().explanation - lazy val errorId: ErrorMessageID = _msg().errorId - - private def toMessage = new Message(errorId) { - val msg = self.msg - val kind = self.kind val explanation = self.explanation } - /** Enclose this message in an `Error` container */ - def error(pos: SourcePosition): Error = - new Error(toMessage, pos) + def append(suffix: => String): Message = mapMsg(_ ++ suffix) - /** Enclose this message in an `Warning` container */ - def warning(pos: SourcePosition): Warning = - new Warning(toMessage, pos) + def mapMsg(f: String => String): Message = new Message(errorId): + val kind = self.kind + lazy val msg = f(self.msg) + lazy val explanation = self.explanation - /** Enclose this message in an `Info` container */ - def info(pos: SourcePosition): Info = - new Info(toMessage, pos) - - /** Enclose this message in an `FeatureWarning` container */ - def featureWarning(pos: SourcePosition): FeatureWarning = - new FeatureWarning(toMessage, pos) - - /** Enclose this message in an `UncheckedWarning` container */ - def uncheckedWarning(pos: SourcePosition): UncheckedWarning = - new UncheckedWarning(toMessage, pos) - - /** Enclose this message in an `DeprecationWarning` container */ - def deprecationWarning(pos: SourcePosition): DeprecationWarning = - new DeprecationWarning(toMessage, pos) - - /** Enclose this message in an `MigrationWarning` container */ - def migrationWarning(pos: SourcePosition): MigrationWarning = - new MigrationWarning(toMessage, pos) + def appendExplanation(suffix: => String): Message = new Message(errorId): + val kind = self.kind + lazy val msg = self.msg + lazy val explanation = self.explanation ++ suffix } /** The fallback `Message` containing no explanation and having no `kind` */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala index af0541556a8a..0f66f7416a54 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala @@ -24,7 +24,7 @@ object MessageContainer { } class MessageContainer( - msgFn: => Message, + val contained: Message, val pos: SourcePosition, val level: Int ) extends Exception with interfaces.Diagnostic { @@ -53,14 +53,6 @@ class MessageContainer( myMsg } - /** This function forces the contained message and returns it */ - def contained: Message = { - if (myContained == null) - myContained = msgFn - - myContained - } - /** A message is non-sensical if it contains references to * tags. Such tags are inserted by the error diagnostic framework if a * message contains references to internally generated error types. Normally diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 51497410991e..2921a52ec134 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -270,10 +270,10 @@ trait Applications extends Compatibility { protected def harmonizeArgs(args: List[TypedArg]): List[TypedArg] /** Signal failure with given message at position of given argument */ - protected def fail(msg: => Message, arg: Arg): Unit + protected def fail(msg: Message, arg: Arg): Unit /** Signal failure with given message at position of the application itself */ - protected def fail(msg: => Message): Unit + protected def fail(msg: Message): Unit protected def appPos: SourcePosition @@ -638,9 +638,9 @@ trait Applications extends Compatibility { def typedArg(arg: Arg, formal: Type): Arg = arg final def addArg(arg: TypedArg, formal: Type): Unit = ok = ok & argOK(arg, formal) def makeVarArg(n: Int, elemFormal: Type): Unit = {} - def fail(msg: => Message, arg: Arg): Unit = + def fail(msg: Message, arg: Arg): Unit = ok = false - def fail(msg: => Message): Unit = + def fail(msg: Message): Unit = ok = false def appPos: SourcePosition = NoSourcePosition @threadUnsafe lazy val normalizedFun: Tree = ref(methRef) @@ -705,12 +705,12 @@ trait Applications extends Compatibility { override def appPos: SourcePosition = app.sourcePos - def fail(msg: => Message, arg: Trees.Tree[T]): Unit = { + def fail(msg: Message, arg: Trees.Tree[T]): Unit = { ctx.error(msg, arg.sourcePos) ok = false } - def fail(msg: => Message): Unit = { + def fail(msg: Message): Unit = { ctx.error(msg, app.sourcePos) ok = false } diff --git a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala index f4d68a3b9be8..2fa1944af980 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -5,7 +5,7 @@ package reporting import org.junit.Assert._ import org.junit.Test import core.Contexts._ -import diagnostic.{ErrorMessageID, ExtendMessage, Message, MessageContainer} +import diagnostic.{ErrorMessageID, Message, MessageContainer} class TestMessageLaziness extends DottyTest { ctx = ctx.fresh.setReporter(new NonchalantReporter) From a0889417527722cf25cf2cb55aae52df137835af Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 10:39:23 +0100 Subject: [PATCH 04/13] Make Message classes not case classes There's no need to have the additional code for the case class machinery in the compiler. --- .../dotc/reporting/diagnostic/Message.scala | 4 +- .../dotc/reporting/diagnostic/messages.scala | 298 +++++++++--------- .../dotty/tools/dotc/util/Signatures.scala | 12 +- 3 files changed, 156 insertions(+), 158 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index 3fcd77ea34dc..d30801422749 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -60,7 +60,7 @@ abstract class Message(val errorId: ErrorMessageID) { self => * forcing its `msg` and `explanation` vals and dropping the implicit context * that was captured in the original message. */ - def persist: Message = new Message (errorId) { + def persist: Message = new Message(errorId) { val kind = self.kind val msg = self.msg val explanation = self.explanation @@ -77,6 +77,8 @@ abstract class Message(val errorId: ErrorMessageID) { self => val kind = self.kind lazy val msg = self.msg lazy val explanation = self.explanation ++ suffix + + override def toString = msg } /** The fallback `Message` containing no explanation and having no `kind` */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 73209060df0b..2992cc777a50 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -147,7 +147,7 @@ object messages { } } - case class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) + class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) { val kind: String = "Syntax" lazy val msg: String = @@ -155,7 +155,7 @@ object messages { |adding a case like - ${hl("case e: Exception =>")} to the block""" } - case class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) + class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchAndFinallyBlockID) { val kind: String = "Syntax" lazy val msg: String = @@ -163,7 +163,7 @@ object messages { |its body in a block; no exceptions are handled.""" } - case class DeprecatedWithOperator()(implicit ctx: Context) + class DeprecatedWithOperator()(implicit ctx: Context) extends Message(DeprecatedWithOperatorID) { val kind: String = "Syntax" lazy val msg: String = @@ -174,7 +174,7 @@ object messages { |semantics between intersection types and using ${hl("with")}.""" } - case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) + class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(CaseClassMissingParamListID) { val kind: String = "Syntax" lazy val msg: String = @@ -186,7 +186,7 @@ object messages { |Or, add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""" } - case class AnonymousFunctionMissingParamType(param: untpd.ValDef, + class AnonymousFunctionMissingParamType(param: untpd.ValDef, args: List[untpd.Tree], tree: untpd.Function, pt: Type) @@ -213,7 +213,7 @@ object messages { lazy val explanation: String = "" } - case class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) + class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) extends Message(WildcardOnTypeArgumentNotAllowedOnNewID) { val kind: String = "Syntax" lazy val msg: String = "Type argument must be fully defined" @@ -246,7 +246,7 @@ object messages { // Type Errors ------------------------------------------------------------ // - case class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) + class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) extends Message(DuplicateBindID) { val kind: String = "Naming" lazy val msg: String = em"duplicate pattern variable: ${bind.name}" @@ -394,7 +394,7 @@ object messages { lazy val explanation: String = "" } - case class EarlyDefinitionsNotSupported()(implicit ctx: Context) + class EarlyDefinitionsNotSupported()(implicit ctx: Context) extends Message(EarlyDefinitionsNotSupportedID) { val kind: String = "Syntax" lazy val msg: String = "Early definitions are not supported; use trait parameters instead" @@ -440,7 +440,7 @@ object messages { } } - case class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) + class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(TopLevelImplicitClassID) { val kind: String = "Syntax" lazy val msg: String = em"""An ${hl("implicit class")} may not be top-level""" @@ -471,7 +471,7 @@ object messages { } } - case class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) + class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(ImplicitCaseClassID) { val kind: String = "Syntax" lazy val msg: String = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" @@ -484,7 +484,7 @@ object messages { |""" + implicitClassRestrictionsText } - case class ImplicitClassPrimaryConstructorArity()(implicit ctx: Context) + class ImplicitClassPrimaryConstructorArity()(implicit ctx: Context) extends Message(ImplicitClassPrimaryConstructorArityID){ val kind: String = "Syntax" lazy val msg: String = "Implicit classes must accept exactly one primary constructor parameter" @@ -500,7 +500,7 @@ object messages { } } - case class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) + class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) extends Message(ObjectMayNotHaveSelfTypeID) { val kind: String = "Syntax" lazy val msg: String = em"""${hl("object")}s must not have a self ${hl("type")}""" @@ -518,7 +518,7 @@ object messages { } } - case class RepeatedModifier(modifier: String)(implicit ctx:Context) + class RepeatedModifier(modifier: String)(implicit ctx:Context) extends Message(RepeatedModifierID) { val kind: String = "Syntax" lazy val msg: String = em"""Repeated modifier $modifier""" @@ -540,7 +540,7 @@ object messages { } } - case class InterpolatedStringError()(implicit ctx:Context) + class InterpolatedStringError()(implicit ctx:Context) extends Message(InterpolatedStringErrorID) { val kind: String = "Syntax" lazy val msg: String = "Error in interpolated string: identifier or block expected" @@ -558,7 +558,7 @@ object messages { } } - case class UnboundPlaceholderParameter()(implicit ctx:Context) + class UnboundPlaceholderParameter()(implicit ctx:Context) extends Message(UnboundPlaceholderParameterID) { val kind: String = "Syntax" lazy val msg: String = em"""Unbound placeholder parameter; incorrect use of ${hl("_")}""" @@ -594,7 +594,7 @@ object messages { |""" } - case class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) + class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) extends Message(IllegalStartSimpleExprID) { val kind: String = "Syntax" lazy val msg: String = em"expression expected but ${Red(illegalToken)} found" @@ -603,7 +603,7 @@ object messages { } } - case class MissingReturnType()(implicit ctx:Context) + class MissingReturnType()(implicit ctx:Context) extends Message(MissingReturnTypeID) { val kind: String = "Syntax" lazy val msg: String = "Missing return type" @@ -615,7 +615,7 @@ object messages { |)}""" } - case class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) + class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) extends Message(MissingReturnTypeWithReturnStatementID) { val kind: String = "Syntax" lazy val msg: String = em"$method has a return statement; it needs a result type" @@ -626,7 +626,7 @@ object messages { |${hl("def good: Int /* explicit return type */ = return 1")}""" } - case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) + class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) extends Message(YieldOrDoExpectedInForComprehensionID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("yield")} or ${hl("do")} expected" @@ -659,7 +659,7 @@ object messages { |""" } - case class ProperDefinitionNotFound()(implicit ctx: Context) + class ProperDefinitionNotFound()(implicit ctx: Context) extends Message(ProperDefinitionNotFoundID) { val kind: String = "Definition Not Found" lazy val msg: String = em"""Proper definition was not found in ${hl("@usecase")}""" @@ -698,7 +698,7 @@ object messages { } } - case class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) + class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) extends Message(ByNameParameterNotSupportedID) { val kind: String = "Syntax" lazy val msg: String = em"By-name parameter type ${tpe} not allowed here." @@ -722,7 +722,7 @@ object messages { |""" } - case class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) + class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) extends Message(WrongNumberOfTypeArgsID) { val kind: String = "Syntax" @@ -764,7 +764,7 @@ object messages { } } - case class IllegalVariableInPatternAlternative()(implicit ctx: Context) + class IllegalVariableInPatternAlternative()(implicit ctx: Context) extends Message(IllegalVariableInPatternAlternativeID) { val kind: String = "Syntax" lazy val msg: String = "Variables are not allowed in alternative patterns" @@ -793,7 +793,7 @@ object messages { } } - case class IdentifierExpected(identifier: String)(implicit ctx: Context) + class IdentifierExpected(identifier: String)(implicit ctx: Context) extends Message(IdentifierExpectedID) { val kind: String = "Syntax" lazy val msg: String = "identifier expected" @@ -814,7 +814,7 @@ object messages { } } - case class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) + class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) extends Message(AuxConstructorNeedsNonImplicitParameterID) { val kind: String = "Syntax" lazy val msg: String = "Auxiliary constructor needs non-implicit parameter list" @@ -830,7 +830,7 @@ object messages { |""" } - case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) + class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) extends Message(IncorrectRepeatedParameterSyntaxID) { val kind: String = "Syntax" lazy val msg: String = "'*' expected" @@ -857,7 +857,7 @@ object messages { |""".stripMargin } - case class IllegalLiteral()(implicit ctx: Context) + class IllegalLiteral()(implicit ctx: Context) extends Message(IllegalLiteralID) { val kind: String = "Syntax" lazy val msg: String = "Illegal literal" @@ -902,21 +902,21 @@ object messages { |""" } - case class MatchCaseUnreachable()(implicit ctx: Context) + class MatchCaseUnreachable()(implicit ctx: Context) extends Message(MatchCaseUnreachableID) { val kind: String = "Match case Unreachable" lazy val msg: String = "Unreachable case" lazy val explanation: String = "" } - case class MatchCaseOnlyNullWarning()(implicit ctx: Context) + class MatchCaseOnlyNullWarning()(implicit ctx: Context) extends Message(MatchCaseOnlyNullWarningID) { val kind: String = "Only null matched" lazy val msg: String = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" lazy val explanation: String = "" } - case class SeqWildcardPatternPos()(implicit ctx: Context) + class SeqWildcardPatternPos()(implicit ctx: Context) extends Message(SeqWildcardPatternPosID) { val kind: String = "Syntax" lazy val msg: String = em"""${hl("_*")} can be used only for last argument""" @@ -940,7 +940,7 @@ object messages { } } - case class IllegalStartOfSimplePattern()(implicit ctx: Context) + class IllegalStartOfSimplePattern()(implicit ctx: Context) extends Message(IllegalStartOfSimplePatternID) { val kind: String = "Syntax" lazy val msg: String = "pattern expected" @@ -1020,14 +1020,14 @@ object messages { } } - case class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) + class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) extends Message(PkgDuplicateSymbolID) { val kind: String = "Duplicate Symbol" lazy val msg: String = em"Trying to define package with same name as $existing" lazy val explanation: String = "" } - case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) + class ExistentialTypesNoLongerSupported()(implicit ctx: Context) extends Message(ExistentialTypesNoLongerSupportedID) { val kind: String = "Syntax" lazy val msg: String = @@ -1050,7 +1050,7 @@ object messages { |""" } - case class UnboundWildcardType()(implicit ctx: Context) + class UnboundWildcardType()(implicit ctx: Context) extends Message(UnboundWildcardTypeID) { val kind: String = "Syntax" lazy val msg: String = "Unbound wildcard type" @@ -1095,7 +1095,7 @@ object messages { |""" } - case class DanglingThisInPath()(implicit ctx: Context) extends Message(DanglingThisInPathID) { + class DanglingThisInPath()(implicit ctx: Context) extends Message(DanglingThisInPathID) { val kind: String = "Syntax" lazy val msg: String = em"""Expected an additional member selection after the keyword ${hl("this")}""" lazy val explanation: String = @@ -1127,7 +1127,7 @@ object messages { |""" } - case class OverridesNothing(member: Symbol)(implicit ctx: Context) + class OverridesNothing(member: Symbol)(implicit ctx: Context) extends Message(OverridesNothingID) { val kind: String = "Reference" lazy val msg: String = em"""${member} overrides nothing""" @@ -1139,7 +1139,7 @@ object messages { |""" } - case class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) + class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) extends Message(OverridesNothingButNameExistsID) { val kind: String = "Reference" lazy val msg: String = em"""${member} has a different signature than the overridden declaration""" @@ -1156,7 +1156,7 @@ object messages { |""" } - case class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) + class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) extends Message(ForwardReferenceExtendsOverDefinitionID) { val kind: String = "Reference" lazy val msg: String = em"${definition.name} is a forward reference extending over the definition of ${value.name}" @@ -1175,7 +1175,7 @@ object messages { |""".stripMargin } - case class ExpectedTokenButFound(expected: Token, found: Token)(implicit ctx: Context) + class ExpectedTokenButFound(expected: Token, found: Token)(implicit ctx: Context) extends Message(ExpectedTokenButFoundID) { val kind: String = "Syntax" @@ -1195,7 +1195,7 @@ object messages { "" } - case class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) + class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) extends Message(MixedLeftAndRightAssociativeOpsID) { val kind: String = "Syntax" lazy val msg: String = @@ -1230,7 +1230,7 @@ object messages { |""".stripMargin } - case class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) + class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) extends Message(CantInstantiateAbstractClassOrTraitID) { val kind: String = "Usage" private val traitOrAbstract = if (isTrait) "a trait" else "abstract" @@ -1249,7 +1249,7 @@ object messages { |""".stripMargin } - case class UnreducibleApplication(tycon: Type)(using Context) extends Message(UnreducibleApplicationID): + class UnreducibleApplication(tycon: Type)(using Context) extends Message(UnreducibleApplicationID): val kind = "Type" lazy val msg = em"unreducible application of higher-kinded type $tycon to wildcard arguments" lazy val explanation = @@ -1257,7 +1257,7 @@ object messages { |Such applications are equivalent to existential types, which are not |supported in Scala 3.""" - case class OverloadedOrRecursiveMethodNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) + class OverloadedOrRecursiveMethodNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) { val kind: String = "Cyclic" lazy val msg: String = em"""Overloaded or recursive $cycleSym needs return type""" @@ -1272,7 +1272,7 @@ object messages { |""".stripMargin } - case class RecursiveValueNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) + class RecursiveValueNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) extends Message(RecursiveValueNeedsResultTypeID) { val kind: String = "Cyclic" lazy val msg: String = em"""Recursive $cycleSym needs type""" @@ -1281,7 +1281,7 @@ object messages { |""".stripMargin } - case class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) + class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) extends Message(CyclicReferenceInvolvingID) { val kind: String = "Cyclic" lazy val msg: String = @@ -1294,7 +1294,7 @@ object messages { |""".stripMargin } - case class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) + class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) extends Message(CyclicReferenceInvolvingImplicitID) { val kind: String = "Cyclic" lazy val msg: String = em"""Cyclic reference involving implicit $cycleSym""" @@ -1306,7 +1306,7 @@ object messages { |""".stripMargin } - case class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(implicit ctx: Context) + class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(implicit ctx: Context) extends Message(SuperQualMustBeParentID) { val kind: String = "Reference" lazy val msg: String = em"""|$qual does not name a parent of $cls""" @@ -1320,7 +1320,7 @@ object messages { |""".stripMargin } - case class VarArgsParamMustComeLast()(implicit ctx: Context) + class VarArgsParamMustComeLast()(implicit ctx: Context) extends Message(IncorrectRepeatedParameterSyntaxID) { val kind: String = "Syntax" lazy val msg: String = em"""${hl("varargs")} parameter must come last""" @@ -1332,7 +1332,7 @@ object messages { import typer.Typer.BindingPrec - case class AmbiguousImport(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec, prevCtx: Context)(implicit ctx: Context) + class AmbiguousImport(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec, prevCtx: Context)(implicit ctx: Context) extends Message(AmbiguousImportID) { /** A string which explains how something was bound; Depending on `prec` this is either @@ -1371,7 +1371,7 @@ object messages { |""" } - case class MethodDoesNotTakeParameters(tree: tpd.Tree)(implicit ctx: Context) + class MethodDoesNotTakeParameters(tree: tpd.Tree)(implicit ctx: Context) extends Message(MethodDoesNotTakeParametersId) { val kind: String = "Reference" @@ -1395,18 +1395,18 @@ object messages { } - case class AmbiguousOverload(tree: tpd.Tree, alts: List[SingleDenotation], pt: Type)( + class AmbiguousOverload(tree: tpd.Tree, val alternatives: List[SingleDenotation], pt: Type)( err: Errors)( implicit ctx: Context) extends Message(AmbiguousOverloadID) { val kind: String = "Reference" - private def all = if (alts.length == 2) "both" else "all" + private def all = if (alternatives.length == 2) "both" else "all" lazy val msg: String = - s"""|Ambiguous overload. The ${err.overloadedAltsStr(alts)} + s"""|Ambiguous overload. The ${err.overloadedAltsStr(alternatives)} |$all match ${err.expectedTypeStr(pt)}""".stripMargin lazy val explanation: String = - em"""|There are ${alts.length} methods that could be referenced as the compiler knows too little + em"""|There are ${alternatives.length} methods that could be referenced as the compiler knows too little |about the expected type. |You may specify the expected type e.g. by |- assigning it to a value with a specified type, or @@ -1414,7 +1414,7 @@ object messages { |""" } - case class ReassignmentToVal(name: Name)(implicit ctx: Context) + class ReassignmentToVal(name: Name)(implicit ctx: Context) extends Message(ReassignmentToValID) { val kind: String = "Reference" lazy val msg: String = em"""Reassignment to val $name""" @@ -1428,7 +1428,7 @@ object messages { |""".stripMargin } - case class TypeDoesNotTakeParameters(tpe: Type, params: List[Trees.Tree[Trees.Untyped]])(implicit ctx: Context) + class TypeDoesNotTakeParameters(tpe: Type, params: List[Trees.Tree[Trees.Untyped]])(implicit ctx: Context) extends Message(TypeDoesNotTakeParametersID) { val kind: String = "Reference" lazy val msg: String = em"$tpe does not take type parameters" @@ -1441,7 +1441,7 @@ object messages { |""" } - case class ParameterizedTypeLacksArguments(psym: Symbol)(implicit ctx: Context) + class ParameterizedTypeLacksArguments(psym: Symbol)(implicit ctx: Context) extends Message(ParameterizedTypeLacksArgumentsID) { val kind: String = "Reference" lazy val msg: String = em"Parameterized $psym lacks argument list" @@ -1451,7 +1451,7 @@ object messages { |""" } - case class VarValParametersMayNotBeCallByName(name: TermName, mutable: Boolean)(implicit ctx: Context) + class VarValParametersMayNotBeCallByName(name: TermName, mutable: Boolean)(implicit ctx: Context) extends Message(VarValParametersMayNotBeCallByNameID) { val kind: String = "Syntax" def varOrVal = if (mutable) em"${hl("var")}" else em"${hl("val")}" @@ -1466,7 +1466,7 @@ object messages { |""" } - case class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) + class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) extends Message(MissingTypeParameterForID) { val kind: String = "Syntax" lazy val msg: String = @@ -1475,7 +1475,7 @@ object messages { lazy val explanation: String = "" } - case class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) + class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) extends Message(MissingTypeParameterInTypeAppID) { val kind: String = "Type Mismatch" def numParams = tpe.typeParams.length @@ -1484,7 +1484,7 @@ object messages { lazy val explanation: String = em"A fully applied type is expected but $tpe takes $numParams $parameters" } - case class DoesNotConformToBound(tpe: Type, which: String, bound: Type)( + class DoesNotConformToBound(tpe: Type, which: String, bound: Type)( err: Errors)(implicit ctx: Context) extends Message(DoesNotConformToBoundID) { val kind: String = "Type Mismatch" @@ -1492,7 +1492,7 @@ object messages { lazy val explanation: String = "" } - case class DoesNotConformToSelfType(category: String, selfType: Type, cls: Symbol, + class DoesNotConformToSelfType(category: String, selfType: Type, cls: Symbol, otherSelf: Type, relation: String, other: Symbol)( implicit ctx: Context) extends Message(DoesNotConformToSelfTypeID) { @@ -1508,7 +1508,7 @@ object messages { """ } - case class DoesNotConformToSelfTypeCantBeInstantiated(tp: Type, selfType: Type)( + class DoesNotConformToSelfTypeCantBeInstantiated(tp: Type, selfType: Type)( implicit ctx: Context) extends Message(DoesNotConformToSelfTypeCantBeInstantiatedID) { val kind: String = "Type Mismatch" @@ -1521,7 +1521,7 @@ object messages { |""" } - case class AbstractMemberMayNotHaveModifier(sym: Symbol, flag: FlagSet)( + class AbstractMemberMayNotHaveModifier(sym: Symbol, flag: FlagSet)( implicit ctx: Context) extends Message(AbstractMemberMayNotHaveModifierID) { val kind: String = "Syntax" @@ -1529,7 +1529,7 @@ object messages { lazy val explanation: String = "" } - case class TopLevelCantBeImplicit(sym: Symbol)( + class TopLevelCantBeImplicit(sym: Symbol)( implicit ctx: Context) extends Message(TopLevelCantBeImplicitID) { val kind: String = "Syntax" @@ -1537,14 +1537,14 @@ object messages { lazy val explanation: String = "" } - case class TypesAndTraitsCantBeImplicit()(implicit ctx: Context) + class TypesAndTraitsCantBeImplicit()(implicit ctx: Context) extends Message(TypesAndTraitsCantBeImplicitID) { val kind: String = "Syntax" lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for types or traits""" lazy val explanation: String = "" } - case class OnlyClassesCanBeAbstract(sym: Symbol)( + class OnlyClassesCanBeAbstract(sym: Symbol)( implicit ctx: Context) extends Message(OnlyClassesCanBeAbstractID) { val kind: String = "Syntax" @@ -1552,7 +1552,7 @@ object messages { lazy val msg: String = em"""${hl("abstract")} modifier can be used only for classes; it should be omitted for abstract members""" } - case class AbstractOverrideOnlyInTraits(sym: Symbol)( + class AbstractOverrideOnlyInTraits(sym: Symbol)( implicit ctx: Context) extends Message(AbstractOverrideOnlyInTraitsID) { val kind: String = "Syntax" @@ -1560,7 +1560,7 @@ object messages { lazy val explanation: String = "" } - case class TraitsMayNotBeFinal(sym: Symbol)( + class TraitsMayNotBeFinal(sym: Symbol)( implicit ctx: Context) extends Message(TraitsMayNotBeFinalID) { val kind: String = "Syntax" @@ -1569,7 +1569,7 @@ object messages { "A trait can never be final since it is abstract and must be extended to be useful." } - case class NativeMembersMayNotHaveImplementation(sym: Symbol)( + class NativeMembersMayNotHaveImplementation(sym: Symbol)( implicit ctx: Context) extends Message(NativeMembersMayNotHaveImplementationID) { val kind: String = "Syntax" @@ -1577,7 +1577,7 @@ object messages { lazy val explanation: String = "" } - case class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( + class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( implicit ctx: Context) extends Message(OnlyClassesCanHaveDeclaredButUndefinedMembersID) { val kind: String = "Syntax" @@ -1589,7 +1589,7 @@ object messages { lazy val explanation: String = s"$varNote" } - case class CannotExtendAnyVal(sym: Symbol)(implicit ctx: Context) + class CannotExtendAnyVal(sym: Symbol)(implicit ctx: Context) extends Message(CannotExtendAnyValID) { val kind: String = "Syntax" lazy val msg: String = em"""$sym cannot extend ${hl("AnyVal")}""" @@ -1600,7 +1600,7 @@ object messages { |""" } - case class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(implicit ctx: Context) + class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(implicit ctx: Context) extends Message(CannotHaveSameNameAsID) { import CannotHaveSameNameAs._ def reasonMessage: String = reason match { @@ -1621,42 +1621,42 @@ object messages { case class DefinedInSelf(self: tpd.ValDef) extends Reason } - case class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context) + class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotDefineInnerID) { val kind: String = "Syntax" lazy val msg: String = em"""Value classes may not define an inner class""" lazy val explanation: String = "" } - case class ValueClassesMayNotDefineNonParameterField(valueClass: Symbol, field: Symbol)(implicit ctx: Context) + class ValueClassesMayNotDefineNonParameterField(valueClass: Symbol, field: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotDefineNonParameterFieldID) { val kind: String = "Syntax" lazy val msg: String = em"""Value classes may not define non-parameter field""" lazy val explanation: String = "" } - case class ValueClassesMayNotDefineASecondaryConstructor(valueClass: Symbol, constructor: Symbol)(implicit ctx: Context) + class ValueClassesMayNotDefineASecondaryConstructor(valueClass: Symbol, constructor: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotDefineASecondaryConstructorID) { val kind: String = "Syntax" lazy val msg: String = em"""Value classes may not define a secondary constructor""" lazy val explanation: String = "" } - case class ValueClassesMayNotContainInitalization(valueClass: Symbol)(implicit ctx: Context) + class ValueClassesMayNotContainInitalization(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotContainInitalizationID) { val kind: String = "Syntax" lazy val msg: String = em"""Value classes may not contain initialization statements""" lazy val explanation: String = "" } - case class ValueClassesMayNotBeAbstract(valueClass: Symbol)(implicit ctx: Context) + class ValueClassesMayNotBeAbstract(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotBeAbstractID) { val kind: String = "Syntax" lazy val msg: String = em"""Value classes may not be ${hl("abstract")}""" lazy val explanation: String = "" } - case class ValueClassesMayNotBeContainted(valueClass: Symbol)(implicit ctx: Context) + class ValueClassesMayNotBeContainted(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotBeContaintedID) { val kind: String = "Syntax" private def localOrMember = if (valueClass.owner.isTerm) "local class" else "member of another class" @@ -1664,14 +1664,14 @@ object messages { lazy val explanation: String = "" } - case class ValueClassesMayNotWrapItself(valueClass: Symbol)(implicit ctx: Context) + class ValueClassesMayNotWrapItself(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassesMayNotWrapItselfID) { val kind: String = "Syntax" lazy val msg: String = """A value class may not wrap itself""" lazy val explanation: String = "" } - case class ValueClassParameterMayNotBeAVar(valueClass: Symbol, param: Symbol)(implicit ctx: Context) + class ValueClassParameterMayNotBeAVar(valueClass: Symbol, param: Symbol)(implicit ctx: Context) extends Message(ValueClassParameterMayNotBeAVarID) { val kind: String = "Syntax" lazy val msg: String = em"""A value class parameter may not be a ${hl("var")}""" @@ -1679,42 +1679,42 @@ object messages { em"""A value class must have exactly one ${hl("val")} parameter.""" } - case class ValueClassNeedsOneValParam(valueClass: Symbol)(implicit ctx: Context) + class ValueClassNeedsOneValParam(valueClass: Symbol)(implicit ctx: Context) extends Message(ValueClassNeedsExactlyOneValParamID) { val kind: String = "Syntax" lazy val msg: String = em"""Value class needs one ${hl("val")} parameter""" lazy val explanation: String = "" } - case class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(implicit ctx: Context) + class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(implicit ctx: Context) extends Message(ValueClassParameterMayNotBeCallByNameID) { val kind: String = "Syntax" lazy val msg: String = s"Value class parameter `${param.name}` may not be call-by-name" lazy val explanation: String = "" } - case class OnlyCaseClassOrCaseObjectAllowed()(implicit ctx: Context) + class OnlyCaseClassOrCaseObjectAllowed()(implicit ctx: Context) extends Message(OnlyCaseClassOrCaseObjectAllowedID) { val kind: String = "Syntax" lazy val msg: String = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" lazy val explanation: String = "" } - case class ExpectedToplevelDef()(implicit ctx: Context) + class ExpectedToplevelDef()(implicit ctx: Context) extends Message(ExpectedTopLevelDefID) { val kind: String = "Syntax" lazy val msg: String = "Expected a toplevel definition" lazy val explanation: String = "" } - case class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context) + class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context) extends Message(SuperCallsNotAllowedInlineableID) { val kind: String = "Syntax" lazy val msg: String = em"Super call not allowed in inlineable $symbol" lazy val explanation: String = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." } - case class NotAPath(tp: Type, usage: String)(using Context) extends Message(NotAPathID): + class NotAPath(tp: Type, usage: String)(using Context) extends Message(NotAPathID): val kind: String = "Type" lazy val msg: String = em"$tp is not a valid $usage, since it is not an immutable path" lazy val explanation: String = @@ -1723,14 +1723,14 @@ object messages { | - a reference to `this`, or | - a selection of an immutable path with an immutable value.""" - case class WrongNumberOfParameters(expected: Int)(implicit ctx: Context) + class WrongNumberOfParameters(expected: Int)(implicit ctx: Context) extends Message(WrongNumberOfParametersID) { val kind: String = "Syntax" lazy val msg: String = s"Wrong number of parameters, expected: $expected" lazy val explanation: String = "" } - case class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) + class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) extends Message(DuplicatePrivateProtectedQualifierID) { val kind: String = "Syntax" lazy val msg: String = "Duplicate private/protected qualifier" @@ -1738,7 +1738,7 @@ object messages { em"It is not allowed to combine `private` and `protected` modifiers even if they are qualified to different scopes" } - case class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) + class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) extends Message(ExpectedStartOfTopLevelDefinitionID) { val kind: String = "Syntax" lazy val msg: String = "Expected start of definition" @@ -1746,7 +1746,7 @@ object messages { em"You have to provide either ${hl("class")}, ${hl("trait")}, ${hl("object")}, or ${hl("enum")} definitions after qualifiers" } - case class NoReturnFromInlineable(owner: Symbol)(implicit ctx: Context) + class NoReturnFromInlineable(owner: Symbol)(implicit ctx: Context) extends Message(NoReturnFromInlineableID) { val kind: String = "Syntax" lazy val msg: String = em"No explicit ${hl("return")} allowed from inlineable $owner" @@ -1757,7 +1757,7 @@ object messages { |""" } - case class ReturnOutsideMethodDefinition(owner: Symbol)(implicit ctx: Context) + class ReturnOutsideMethodDefinition(owner: Symbol)(implicit ctx: Context) extends Message(ReturnOutsideMethodDefinitionID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("return")} outside method definition" @@ -1767,7 +1767,7 @@ object messages { |""" } - case class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) + class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) extends Message(ExtendFinalClassID) { val kind: String = "Syntax" lazy val msg: String = em"$clazz cannot extend ${hl("final")} $finalClazz" @@ -1775,7 +1775,7 @@ object messages { em"""A class marked with the ${hl("final")} keyword cannot be extended""" } - case class ExpectedTypeBoundOrEquals(found: Token)(implicit ctx: Context) + class ExpectedTypeBoundOrEquals(found: Token)(implicit ctx: Context) extends Message(ExpectedTypeBoundOrEqualsID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" @@ -1793,7 +1793,7 @@ object messages { |""" } - case class ClassAndCompanionNameClash(cls: Symbol, other: Symbol)(implicit ctx: Context) + class ClassAndCompanionNameClash(cls: Symbol, other: Symbol)(implicit ctx: Context) extends Message(ClassAndCompanionNameClashID) { val kind: String = "Naming" lazy val msg: String = em"Name clash: both ${cls.owner} and its companion object defines ${cls.name.stripModuleClassSuffix}" @@ -1803,7 +1803,7 @@ object messages { | - ${other.owner} defines ${other}""" } - case class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) + class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) extends Message(TailrecNotApplicableID) { val kind: String = "Syntax" lazy val msg: String = { @@ -1818,7 +1818,7 @@ object messages { lazy val explanation: String = "" } - case class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol])(implicit ctx: Context) + class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol])(implicit ctx: Context) extends Message(FailureToEliminateExistentialID) { val kind: String = "Compatibility" lazy val msg: String = "Failure to eliminate existential type. Proceed at own risk." @@ -1830,7 +1830,7 @@ object messages { } } - case class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(implicit ctx: Context) + class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(implicit ctx: Context) extends Message(OnlyFunctionsCanBeFollowedByUnderscoreID) { val kind: String = "Syntax" lazy val msg: String = em"Only function types can be followed by ${hl("_")} but the current expression has type $tp" @@ -1839,7 +1839,7 @@ object messages { |To convert to a function value, you need to explicitly write ${hl("() => x")}""" } - case class MissingEmptyArgumentList(method: Symbol)(implicit ctx: Context) + class MissingEmptyArgumentList(method: Symbol)(implicit ctx: Context) extends Message(MissingEmptyArgumentListID) { val kind: String = "Syntax" lazy val msg: String = em"$method must be called with ${hl("()")} argument" @@ -1857,21 +1857,21 @@ object messages { } } - case class DuplicateNamedTypeParameter(name: Name)(implicit ctx: Context) + class DuplicateNamedTypeParameter(name: Name)(implicit ctx: Context) extends Message(DuplicateNamedTypeParameterID) { val kind: String = "Syntax" lazy val msg: String = em"Type parameter $name was defined multiple times." lazy val explanation: String = "" } - case class UndefinedNamedTypeParameter(undefinedName: Name, definedNames: List[Name])(implicit ctx: Context) + class UndefinedNamedTypeParameter(undefinedName: Name, definedNames: List[Name])(implicit ctx: Context) extends Message(UndefinedNamedTypeParameterID) { val kind: String = "Syntax" lazy val msg: String = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." lazy val explanation: String = "" } - case class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends Message(IllegalStartOfStatementID) { + class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends Message(IllegalStartOfStatementID) { val kind: String = "Syntax" lazy val msg: String = { val addendum = if (isModifier) ": no modifiers allowed here" else "" @@ -1880,7 +1880,7 @@ object messages { lazy val explanation: String = "A statement is either an import, a definition or an expression." } - case class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends Message(TraitIsExpectedID) { + class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends Message(TraitIsExpectedID) { val kind: String = "Syntax" lazy val msg: String = em"$symbol is not a trait" lazy val explanation: String = { @@ -1908,13 +1908,13 @@ object messages { } } - case class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends Message(TraitRedefinedFinalMethodFromAnyRefID) { + class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends Message(TraitRedefinedFinalMethodFromAnyRefID) { val kind: String = "Syntax" lazy val msg: String = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." lazy val explanation: String = "" } - case class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends Message(PackageNameAlreadyDefinedID) { + class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends Message(PackageNameAlreadyDefinedID) { val kind: String = "Naming" lazy val (where, or) = if pkg.associatedFile == null then ("", "") @@ -1926,7 +1926,7 @@ object messages { |Rename either one of them$or.""" } - case class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) + class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) extends Message(UnapplyInvalidNumberOfArgumentsID) { val kind: String = "Syntax" lazy val msg: String = em"Wrong number of argument patterns for $qual; expected: ($argTypes%, %)" @@ -1939,7 +1939,7 @@ object messages { |""".stripMargin } - case class UnapplyInvalidReturnType(unapplyResult: Type, unapplyName: Symbol#ThisName)(implicit ctx: Context) + class UnapplyInvalidReturnType(unapplyResult: Type, unapplyName: Symbol#ThisName)(implicit ctx: Context) extends Message(UnapplyInvalidReturnTypeID) { val kind = "Type Mismatch" lazy val msg = @@ -1995,14 +1995,14 @@ object messages { """.stripMargin } - case class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends Message(StaticFieldsOnlyAllowedInObjectsID) { + class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends Message(StaticFieldsOnlyAllowedInObjectsID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}." lazy val explanation: String = em"${hl("@static")} members are only allowed inside objects." } - case class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends Message(StaticFieldsShouldPrecedeNonStaticID) { + class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends Message(StaticFieldsShouldPrecedeNonStaticID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined before non-static fields." lazy val explanation: String = { @@ -2040,7 +2040,7 @@ object messages { } } - case class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) extends Message(BadSymbolicReferenceID) { + class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) extends Message(BadSymbolicReferenceID) { val kind: String = "Reference" lazy val msg: String = { @@ -2060,7 +2060,7 @@ object messages { lazy val explanation: String = "" } - case class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends Message(UnableToExtendSealedClassID) { + class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends Message(UnableToExtendSealedClassID) { val kind: String = "Syntax" lazy val msg: String = em"Cannot extend ${hl("sealed")} $pclazz in a different source file" lazy val explanation: String = "A sealed class or trait can only be extended in the same file as its declaration" @@ -2078,7 +2078,7 @@ object messages { |whose behavior may have changed since version change.""" } - case class SymbolChangedSemanticsInVersion( + class SymbolChangedSemanticsInVersion( symbol: Symbol, migrationVersion: ScalaVersion )(implicit ctx: Context) extends Message(SymbolChangedSemanticsInVersionID) { @@ -2091,7 +2091,7 @@ object messages { } } - case class UnableToEmitSwitch(tooFewCases: Boolean)(implicit ctx: Context) + class UnableToEmitSwitch(tooFewCases: Boolean)(implicit ctx: Context) extends Message(UnableToEmitSwitchID) { val kind: String = "Syntax" def tooFewStr: String = if (tooFewCases) " since there are not enough cases" else "" @@ -2121,14 +2121,14 @@ object messages { } } - case class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) extends Message(MissingCompanionForStaticID) { + class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) extends Message(MissingCompanionForStaticID) { val kind: String = "Syntax" lazy val msg: String = em"${member.owner} does not have a companion class" lazy val explanation: String = em"An object that contains ${hl("@static")} members must have a companion class." } - case class PolymorphicMethodMissingTypeInParent(rsym: Symbol, parentSym: Symbol)(implicit ctx: Context) + class PolymorphicMethodMissingTypeInParent(rsym: Symbol, parentSym: Symbol)(implicit ctx: Context) extends Message(PolymorphicMethodMissingTypeInParentID) { val kind: String = "Syntax" lazy val msg: String = em"Polymorphic refinement $rsym without matching type in parent $parentSym is no longer allowed" @@ -2138,14 +2138,14 @@ object messages { |polymorphic methods.""" } - case class ParamsNoInline(owner: Symbol)(implicit ctx: Context) + class ParamsNoInline(owner: Symbol)(implicit ctx: Context) extends Message(ParamsNoInlineID) { val kind: String = "Syntax" lazy val msg: String = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" lazy val explanation: String = "" } - case class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends Message(JavaSymbolIsNotAValueID) { + class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends Message(JavaSymbolIsNotAValueID) { val kind: String = "Type Mismatch" lazy val msg: String = { val kind = @@ -2157,7 +2157,7 @@ object messages { lazy val explanation: String = "" } - case class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends Message(DoubleDefinitionID) { + class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends Message(DoubleDefinitionID) { val kind: String = "Duplicate Symbol" lazy val msg: String = { def nameAnd = if (decl.name != previousDecl.name) " name and" else "" @@ -2203,13 +2203,13 @@ object messages { lazy val explanation: String = "" } - case class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends Message(ImportRenamedTwiceID) { + class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends Message(ImportRenamedTwiceID) { val kind: String = "Syntax" lazy val msg: String = s"${ident.show} is renamed twice on the same import line." lazy val explanation: String = "" } - case class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends Message(TypeTestAlwaysSucceedsID) { + class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends Message(TypeTestAlwaysSucceedsID) { val kind: String = "Syntax" lazy val msg: String = { val addendum = @@ -2221,7 +2221,7 @@ object messages { } // Relative of CyclicReferenceInvolvingImplicit and RecursiveValueNeedsResultType - case class TermMemberNeedsResultTypeForImplicitSearch(cycleSym: Symbol)(implicit ctx: Context) + class TermMemberNeedsResultTypeForImplicitSearch(cycleSym: Symbol)(implicit ctx: Context) extends Message(TermMemberNeedsNeedsResultTypeForImplicitSearchID) { val kind: String = "Cyclic" lazy val msg: String = em"""$cycleSym needs result type because its right-hand side attempts implicit search""" @@ -2231,13 +2231,13 @@ object messages { |""".stripMargin } - case class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends Message(ClassCannotExtendEnumID) { + class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends Message(ClassCannotExtendEnumID) { val kind: String = "Syntax" lazy val msg: String = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" lazy val explanation: String = "" } - case class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends Message(NotAnExtractorID) { + class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends Message(NotAnExtractorID) { val kind: String = "Syntax" lazy val msg: String = em"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method" lazy val explanation: String = @@ -2251,14 +2251,14 @@ object messages { |This mechanism is used for instance in pattern ${hl("case List(x1, ..., xn)")}""".stripMargin } - case class MemberWithSameNameAsStatic()(implicit val ctx: Context) + class MemberWithSameNameAsStatic()(implicit val ctx: Context) extends Message(MemberWithSameNameAsStaticID) { val kind: String = "Syntax" lazy val msg: String = em"Companion classes cannot define members with same name as a ${hl("@static")} member" lazy val explanation: String = "" } - case class PureExpressionInStatementPosition(stat: untpd.Tree, exprOwner: Symbol)(implicit ctx: Context) + class PureExpressionInStatementPosition(stat: untpd.Tree, exprOwner: Symbol)(implicit ctx: Context) extends Message(PureExpressionInStatementPositionID) { val kind = "Potential Issue" lazy val msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" @@ -2267,28 +2267,28 @@ object messages { |It can be removed without changing the semantics of the program. This may indicate an error.""".stripMargin } - case class TraitCompanionWithMutableStatic()(implicit val ctx: Context) + class TraitCompanionWithMutableStatic()(implicit val ctx: Context) extends Message(TraitCompanionWithMutableStaticID) { val kind: String = "Syntax" lazy val msg: String = em"Companion of traits cannot define mutable @static fields" lazy val explanation: String = "" } - case class LazyStaticField()(implicit val ctx: Context) + class LazyStaticField()(implicit val ctx: Context) extends Message(LazyStaticFieldID) { val kind: String = "Syntax" lazy val msg: String = em"Lazy @static fields are not supported" lazy val explanation: String = "" } - case class StaticOverridingNonStaticMembers()(implicit val ctx: Context) + class StaticOverridingNonStaticMembers()(implicit val ctx: Context) extends Message(StaticOverridingNonStaticMembersID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("@static")} members cannot override or implement non-static ones" lazy val explanation: String = "" } - case class OverloadInRefinement(rsym: Symbol)(implicit val ctx: Context) + class OverloadInRefinement(rsym: Symbol)(implicit val ctx: Context) extends Message(OverloadInRefinementID) { val kind: String = "Overload" lazy val msg: String = "Refinements cannot introduce overloaded definitions" @@ -2297,7 +2297,7 @@ object messages { |Refinements cannot contain overloaded definitions.""".stripMargin } - case class NoMatchingOverload(alternatives: List[SingleDenotation], pt: Type)( + class NoMatchingOverload(val alternatives: List[SingleDenotation], pt: Type)( err: Errors)(implicit val ctx: Context) extends Message(NoMatchingOverloadID) { val kind: String = "Type Mismatch" @@ -2306,7 +2306,7 @@ object messages { |match ${err.expectedTypeStr(pt)}""" lazy val explanation: String = "" } - case class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) + class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) extends Message(StableIdentPatternID) { val kind: String = "Type" lazy val msg: String = @@ -2314,7 +2314,7 @@ object messages { lazy val explanation: String = "" } - case class IllegalSuperAccessor(base: Symbol, memberName: Name, + class IllegalSuperAccessor(base: Symbol, memberName: Name, acc: Symbol, accTp: Type, other: Symbol, otherTp: Type)(implicit val ctx: Context) extends Message(IllegalSuperAccessorID) { val kind: String = "Reference" @@ -2370,7 +2370,7 @@ object messages { lazy val explanation: String = "" } - case class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) + class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) extends Message(TraitParameterUsedAsParentPrefixID) { val kind: String = "Reference" lazy val msg: String = @@ -2386,7 +2386,7 @@ object messages { |""".stripMargin } - case class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) + class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) extends Message(UnknownNamedEnclosingClassOrObjectID) { val kind: String = "Reference" lazy val msg: String = @@ -2400,21 +2400,21 @@ object messages { """.stripMargin } - case class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context) + class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context) extends Message(IllegalCyclicTypeReferenceID) { val kind: String = "Cyclic" lazy val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" lazy val explanation: String = "" } - case class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) + class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) extends Message(ErasedTypesCanOnlyBeFunctionTypesID) { val kind: String = "Syntax" lazy val msg: String = "Types with erased keyword can only be function types `(erased ...) => ...`" lazy val explanation: String = "" } - case class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) + class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(CaseClassMissingNonImplicitParamListID) { val kind: String = "Syntax" lazy val msg: String = @@ -2426,7 +2426,7 @@ object messages { | add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""".stripMargin } - case class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context) + class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context) extends Message(EnumerationsShouldNotBeEmptyID) { val kind: String = "Syntax" lazy val msg: String = "Enumerations must contain at least one case" @@ -2440,7 +2440,7 @@ object messages { |""".stripMargin } - case class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context) + class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context) extends Message(AbstractCannotBeUsedForObjectsID) { val kind: String = "Syntax" lazy val msg: String = em"${hl("abstract")} modifier cannot be used for objects" @@ -2456,7 +2456,7 @@ object messages { |""".stripMargin } - case class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context) + class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context) extends Message(ModifierRedundantForObjectsID) { val kind: String = "Syntax" lazy val msg: String = em"${hl(modifier)} modifier is redundant for objects" @@ -2468,7 +2468,7 @@ object messages { |""".stripMargin } - case class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) + class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) extends Message(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { val kind: String = "Syntax" lazy val msg: String = i"explicit extends clause needed because both enum case and enum class have type parameters" @@ -2483,7 +2483,7 @@ object messages { |""".stripMargin } - case class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) + class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) extends Message(IllegalRedefinitionOfStandardKindID) { val kind: String = "Syntax" lazy val msg: String = em"illegal redefinition of standard $kindType $name" @@ -2494,7 +2494,7 @@ object messages { |""".stripMargin } - case class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) + class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) extends Message(NoExtensionMethodAllowedID) { val kind: String = "Syntax" lazy val msg: String = em"No extension method allowed here, since collective parameters are given" @@ -2506,7 +2506,7 @@ object messages { |""".stripMargin } - case class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) + class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) extends Message(ExtensionMethodCannotHaveTypeParamsID) { val kind: String = "Syntax" lazy val msg: String = i"Extension method cannot have type parameters since some were already given previously" @@ -2519,7 +2519,7 @@ object messages { |""".stripMargin } - case class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) + class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) extends Message(ExtensionCanOnlyHaveDefsID) { val kind: String = "Syntax" lazy val msg: String = em"Only methods allowed here, since collective parameters are given" @@ -2530,7 +2530,7 @@ object messages { |""".stripMargin } - case class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) + class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) extends Message(UnexpectedPatternForSummonFromID) { val kind: String = "Syntax" lazy val msg: String = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" @@ -2551,7 +2551,7 @@ object messages { |""".stripMargin } - case class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) + class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) extends Message(AnonymousInstanceCannotBeEmptyID) { val kind: String = "Syntax" lazy val msg: String = i"anonymous instance must implement a type or have at least one extension method" @@ -2562,7 +2562,7 @@ object messages { |""".stripMargin } - case class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) + class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) extends Message(TypeSpliceInValPatternID) { val kind: String = "Syntax" lazy val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead." @@ -2573,7 +2573,7 @@ object messages { |""".stripMargin } - case class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) + class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) extends Message(ModifierNotAllowedForDefinitionID) { val kind: String = "Syntax" lazy val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition" diff --git a/compiler/src/dotty/tools/dotc/util/Signatures.scala b/compiler/src/dotty/tools/dotc/util/Signatures.scala index d59080437627..26e2bc04871a 100644 --- a/compiler/src/dotty/tools/dotc/util/Signatures.scala +++ b/compiler/src/dotty/tools/dotc/util/Signatures.scala @@ -162,14 +162,10 @@ object Signatures { */ private def alternativesFromError(err: ErrorType, params: List[tpd.Tree])(implicit ctx: Context): (Int, List[SingleDenotation]) = { val alternatives = - err.msg match { - case messages.AmbiguousOverload(_, alternatives, _) => - alternatives - case messages.NoMatchingOverload(alternatives, _) => - alternatives - case _ => - Nil - } + err.msg match + case msg: messages.AmbiguousOverload => msg.alternatives + case msg: messages.NoMatchingOverload => msg.alternatives + case _ => Nil // If the user writes `foo(bar, )`, the typer will insert a synthetic // `null` parameter: `foo(bar, null)`. This may influence what's the "best" From d0679b0b596196a3271924fcd044996e89be6dd2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 11:15:14 +0100 Subject: [PATCH 05/13] More fixes Fixes in files that were not saved before --- compiler/src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../src/dotty/tools/dotc/core/TypeErrors.scala | 4 ++-- compiler/src/dotty/tools/dotc/core/TypeOps.scala | 2 +- .../src/dotty/tools/dotc/parsing/Parsers.scala | 14 +++++++------- .../tools/dotc/reporting/diagnostic/messages.scala | 2 +- .../dotty/tools/dotc/typer/ErrorReporting.scala | 6 +++--- .../tools/languageserver/DottyLanguageServer.scala | 4 ++-- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 0759fd2e1080..af6e7d218460 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -300,7 +300,7 @@ trait Symbols { this: Context => */ def newSkolem(tp: Type): TermSymbol = newSymbol(defn.RootClass, nme.SKOLEM, SyntheticArtifact | NonMember | Permanent, tp) - def newErrorSymbol(owner: Symbol, name: Name, msg: => Message): Symbol = { + def newErrorSymbol(owner: Symbol, name: Name, msg: Message): Symbol = { val errType = ErrorType(msg) newSymbol(owner, name, SyntheticArtifact, if (name.isTypeName) TypeAlias(errType) else errType) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala index 20372063d249..053d5c32a80a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala @@ -10,7 +10,7 @@ import Contexts._ import SymDenotations._ import Denotations._ import Decorators._ -import reporting.diagnostic.Message +import reporting.diagnostic.{Message, NoExplanation} import reporting.diagnostic.messages._ import ast.untpd import config.Printers.cyclicErrors @@ -69,7 +69,7 @@ class RecursionOverflow(val op: String, details: => String, val previous: Throwa (rs.map(_.explanation): List[String]).mkString("\n ", "\n| ", "") } - override def produceMessage(implicit ctx: Context): Message = { + override def produceMessage(implicit ctx: Context): Message = NoExplanation { val mostCommon = recursions.groupBy(_.op).toList.maxBy(_._2.map(_.weight).sum)._2.reverse s"""Recursion limit exceeded. |Maybe there is an illegal cyclic reference? diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index c1c0d0a39e1d..25662025970a 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -516,7 +516,7 @@ trait TypeOps { this: Context => // TODO: Make standalone object. def dynamicsEnabled: Boolean = featureEnabled(nme.dynamics) - def testScala2CompatMode(msg: => Message, pos: SourcePosition, replace: => Unit = ()): Boolean = { + def testScala2CompatMode(msg: Message, pos: SourcePosition, replace: => Unit = ()): Boolean = { if (scala2CompatMode) { migrationWarning(msg, pos) replace diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 479324873cdd..8072e5a95172 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -131,7 +131,7 @@ object Parsers { /** Issue an error at given offset if beyond last error offset * and update lastErrorOffset. */ - def syntaxError(msg: => Message, offset: Int = in.offset): Unit = + def syntaxError(msg: Message, offset: Int = in.offset): Unit = if (offset > lastErrorOffset) { val length = if (offset == in.offset && in.name != null) in.name.show.length else 0 syntaxError(msg, Span(offset, offset + length)) @@ -141,7 +141,7 @@ object Parsers { /** Unconditionally issue an error at given span, without * updating lastErrorOffset. */ - def syntaxError(msg: => Message, span: Span): Unit = + def syntaxError(msg: Message, span: Span): Unit = ctx.error(msg, source.atSpan(span)) def unimplementedExpr(implicit ctx: Context): Select = @@ -308,23 +308,23 @@ object Parsers { } } - def warning(msg: => Message, sourcePos: SourcePosition): Unit = + def warning(msg: Message, sourcePos: SourcePosition): Unit = ctx.warning(msg, sourcePos) - def warning(msg: => Message, offset: Int = in.offset): Unit = + def warning(msg: Message, offset: Int = in.offset): Unit = ctx.warning(msg, source.atSpan(Span(offset))) - def deprecationWarning(msg: => Message, offset: Int = in.offset): Unit = + def deprecationWarning(msg: Message, offset: Int = in.offset): Unit = ctx.deprecationWarning(msg, source.atSpan(Span(offset))) /** Issue an error at current offset that input is incomplete */ - def incompleteInputError(msg: => Message): Unit = + def incompleteInputError(msg: Message): Unit = ctx.incompleteInputError(msg, source.atSpan(Span(in.offset))) /** If at end of file, issue an incompleteInputError. * Otherwise issue a syntax error and skip to next safe point. */ - def syntaxErrorOrIncomplete(msg: => Message, offset: Int = in.offset): Unit = + def syntaxErrorOrIncomplete(msg: Message, offset: Int = in.offset): Unit = if (in.token == EOF) incompleteInputError(msg) else { syntaxError(msg, offset) diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 2992cc777a50..6f0a44ac3107 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -2258,7 +2258,7 @@ object messages { lazy val explanation: String = "" } - class PureExpressionInStatementPosition(stat: untpd.Tree, exprOwner: Symbol)(implicit ctx: Context) + class PureExpressionInStatementPosition(stat: untpd.Tree, val exprOwner: Symbol)(implicit ctx: Context) extends Message(PureExpressionInStatementPositionID) { val kind = "Potential Issue" lazy val msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index 268100b12d1a..e3cf5c03e875 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -16,16 +16,16 @@ object ErrorReporting { import tpd._ - def errorTree(tree: untpd.Tree, msg: => Message, pos: SourcePosition)(implicit ctx: Context): tpd.Tree = + def errorTree(tree: untpd.Tree, msg: Message, pos: SourcePosition)(implicit ctx: Context): tpd.Tree = tree.withType(errorType(msg, pos)) - def errorTree(tree: untpd.Tree, msg: => Message)(implicit ctx: Context): tpd.Tree = + def errorTree(tree: untpd.Tree, msg: Message)(implicit ctx: Context): tpd.Tree = errorTree(tree, msg, tree.sourcePos) def errorTree(tree: untpd.Tree, msg: TypeError, pos: SourcePosition)(implicit ctx: Context): tpd.Tree = tree.withType(errorType(msg, pos)) - def errorType(msg: => Message, pos: SourcePosition)(implicit ctx: Context): ErrorType = { + def errorType(msg: Message, pos: SourcePosition)(implicit ctx: Context): ErrorType = { ctx.error(msg, pos) ErrorType(msg) } diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index e42805a55bd1..d2c1eaea6387 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -733,8 +733,8 @@ object DottyLanguageServer { private def displayMessage(message: Message, sourceFile: SourceFile)(implicit ctx: Context): Boolean = { if (isWorksheet(sourceFile)) { message match { - case messages.PureExpressionInStatementPosition(_, exprOwner) => - val ownerSym = if (exprOwner.isLocalDummy) exprOwner.owner else exprOwner + case msg: messages.PureExpressionInStatementPosition => + val ownerSym = if (msg.exprOwner.isLocalDummy) msg.exprOwner.owner else msg.exprOwner !isWorksheetWrapper(ownerSym) case _ => true From 540cdec28809da826681a45fa01998623fb70068 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 11:21:05 +0100 Subject: [PATCH 06/13] Rename MessageContainer -> Diagnostic --- .../dotc/interactive/InteractiveDriver.scala | 6 +-- .../tools/dotc/printing/Formatting.scala | 4 +- .../dotc/reporting/ConsoleReporter.scala | 24 +++++----- .../reporting/HideNonSensicalMessages.scala | 8 ++-- .../dotc/reporting/MessageRendering.scala | 20 ++++---- .../dotty/tools/dotc/reporting/Reporter.scala | 44 +++++++++--------- .../tools/dotc/reporting/StoreReporter.scala | 14 +++--- .../dotc/reporting/ThrowingReporter.scala | 8 ++-- .../reporting/UniqueMessagePositions.scala | 14 +++--- ...essageContainer.scala => Diagnostic.scala} | 10 ++-- .../dotc/reporting/diagnostic/Message.scala | 8 ++-- .../dotc/reporting/diagnostic/messages.scala | 8 ++-- .../src/dotty/tools/repl/ParseResult.scala | 4 +- .../src/dotty/tools/repl/ReplDriver.scala | 8 ++-- compiler/src/dotty/tools/repl/results.scala | 6 +-- .../tools/dotc/EntryPointsTest.scala.disabled | 4 +- .../dotc/reporting/TestMessageLaziness.scala | 6 +-- .../tools/dotc/reporting/TestReporter.scala | 46 +++++++++---------- .../dotty/tools/vulpix/ParallelTesting.scala | 4 +- .../languageserver/DottyLanguageServer.scala | 16 +++---- sbt-bridge/src/xsbt/DelegatingReporter.java | 7 ++- .../tasty-interpreter/Test.scala | 4 +- 22 files changed, 136 insertions(+), 137 deletions(-) rename compiler/src/dotty/tools/dotc/reporting/diagnostic/{MessageContainer.scala => Diagnostic.scala} (91%) diff --git a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala index 17a0907184c2..44e93c830d8e 100644 --- a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala +++ b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala @@ -17,7 +17,7 @@ import ast.{Trees, tpd} import core._, core.Decorators._ import Contexts._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._ import classpath._ -import reporting._, reporting.diagnostic.MessageContainer +import reporting._, reporting.diagnostic.Diagnostic import util._ /** A Driver subclass designed to be used from IDEs */ @@ -138,9 +138,9 @@ class InteractiveDriver(val settings: List[String]) extends Driver { (fromSource ++ fromClassPath).distinct } - def run(uri: URI, sourceCode: String): List[MessageContainer] = run(uri, toSource(uri, sourceCode)) + def run(uri: URI, sourceCode: String): List[Diagnostic] = run(uri, toSource(uri, sourceCode)) - def run(uri: URI, source: SourceFile): List[MessageContainer] = { + def run(uri: URI, source: SourceFile): List[Diagnostic] = { val previousCtx = myCtx try { val reporter = diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index 25a6430b7d15..d0d189f0e212 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -6,7 +6,7 @@ import Texts._, Types._, Flags._, Symbols._, Contexts._ import collection.mutable import Decorators._ import scala.util.control.NonFatal -import reporting.diagnostic.MessageContainer +import reporting.diagnostic.Diagnostic import util.DiffUtil import Highlighting._ @@ -88,7 +88,7 @@ object Formatting { } private def wrapNonSensical(arg: Any, str: String)(implicit ctx: Context): String = { - import MessageContainer._ + import Diagnostic._ def isSensical(arg: Any): Boolean = arg match { case tpe: Type => tpe.exists && !tpe.isErroneous diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 0979e1c40dfa..43eedeef1820 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -4,7 +4,7 @@ package reporting import core.Contexts._ import java.io.{ BufferedReader, PrintWriter } -import diagnostic.MessageContainer +import diagnostic.Diagnostic import diagnostic.messages.{ Error, ConditionalWarning } /** @@ -15,28 +15,28 @@ class ConsoleReporter( writer: PrintWriter = new PrintWriter(Console.err, true) ) extends AbstractReporter { - import MessageContainer._ + import Diagnostic._ /** Prints the message. */ def printMessage(msg: String): Unit = { writer.print(msg + "\n"); writer.flush() } /** Prints the message with the given position indication. */ - def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { - val didPrint = m match { - case m: Error => - printMessage(messageAndPos(m.contained, m.pos, diagnosticLevel(m))) + def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = { + val didPrint = dia match { + case dia: Error => + printMessage(messageAndPos(dia.contained, dia.pos, diagnosticLevel(dia))) if (ctx.settings.Xprompt.value) Reporter.displayPrompt(reader, writer) true - case m: ConditionalWarning if !m.enablingOption.value => + case dia: ConditionalWarning if !dia.enablingOption.value => false - case m => - printMessage(messageAndPos(m.contained, m.pos, diagnosticLevel(m))) + case dia => + printMessage(messageAndPos(dia.contained, dia.pos, diagnosticLevel(dia))) true } - if (didPrint && ctx.shouldExplain(m)) - printMessage(explanation(m.contained)) - else if (didPrint && m.contained.explanation.nonEmpty) + if (didPrint && ctx.shouldExplain(dia)) + printMessage(explanation(dia.contained)) + else if (didPrint && dia.contained.explanation.nonEmpty) printMessage("\nlonger explanation available when compiling with `-explain`") } diff --git a/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala b/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala index ba1ab9b33beb..beb2331db1c7 100644 --- a/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala @@ -3,7 +3,7 @@ package dotc package reporting import core.Contexts.Context -import diagnostic.MessageContainer +import diagnostic.Diagnostic /** * This trait implements `isHidden` so that we avoid reporting non-sensical messages. @@ -12,9 +12,9 @@ trait HideNonSensicalMessages extends Reporter { /** Hides non-sensical messages, unless we haven't reported any error yet or * `-Yshow-suppressed-errors` is set. */ - override def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean = - super.isHidden(m) || { - m.isNonSensical && + override def isHidden(dia: Diagnostic)(implicit ctx: Context): Boolean = + super.isHidden(dia) || { + dia.isNonSensical && hasErrors && // if there are no errors yet, report even if diagnostic is non-sensical !ctx.settings.YshowSuppressedErrors.value } diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index ef912c3bf61e..5bcb25f692e7 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -8,7 +8,7 @@ import core.Contexts.Context import core.Decorators._ import printing.Highlighting.{Blue, Red, Yellow} import printing.SyntaxHighlighting -import diagnostic.{ErrorMessageID, Message, MessageContainer} +import diagnostic.{ErrorMessageID, Message, Diagnostic} import diagnostic.messages._ import util.SourcePosition import scala.internal.Chars.{ LF, CR, FF, SU } @@ -167,14 +167,14 @@ trait MessageRendering { Yellow(str).show } - def diagnosticLevel(cont: MessageContainer): String = - cont match { - case m: Error => "Error" - case m: FeatureWarning => "Feature Warning" - case m: DeprecationWarning => "Deprecation Warning" - case m: UncheckedWarning => "Unchecked Warning" - case m: MigrationWarning => "Migration Warning" - case m: Warning => "Warning" - case m: Info => "Info" + def diagnosticLevel(dia: Diagnostic): String = + dia match { + case dia: Error => "Error" + case dia: FeatureWarning => "Feature Warning" + case dia: DeprecationWarning => "Deprecation Warning" + case dia: UncheckedWarning => "Unchecked Warning" + case dia: MigrationWarning => "Migration Warning" + case dia: Warning => "Warning" + case dia: Info => "Info" } } diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index d8e19b2310ca..a0bcc3278a15 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -25,20 +25,20 @@ object Reporter { /** Convert a SimpleReporter into a real Reporter */ def fromSimpleReporter(simple: interfaces.SimpleReporter): Reporter = new Reporter with UniqueMessagePositions with HideNonSensicalMessages { - override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = m match { - case m: ConditionalWarning if !m.enablingOption.value => + override def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = dia match { + case dia: ConditionalWarning if !dia.enablingOption.value => case _ => - simple.report(m) + simple.report(dia) } } /** A reporter that ignores reports, and doesn't record errors */ @sharable object NoReporter extends Reporter { - def doReport(m: MessageContainer)(implicit ctx: Context): Unit = () - override def report(m: MessageContainer)(implicit ctx: Context): Unit = () + def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = () + override def report(dia: Diagnostic)(implicit ctx: Context): Unit = () } - type ErrorHandler = (MessageContainer, Context) => Unit + type ErrorHandler = (Diagnostic, Context) => Unit private val defaultIncompleteHandler: ErrorHandler = (mc, ctx) => ctx.reporter.report(mc)(ctx) @@ -192,7 +192,7 @@ abstract class Reporter extends interfaces.ReporterResult { import Reporter._ /** Report a diagnostic */ - def doReport(m: MessageContainer)(implicit ctx: Context): Unit + def doReport(dia: Diagnostic)(implicit ctx: Context): Unit /** Whether very long lines can be truncated. This exists so important * debugging information (like printing the classpath) is not rendered @@ -261,25 +261,25 @@ abstract class Reporter extends interfaces.ReporterResult { var unreportedWarnings: Map[String, Int] = Map.empty - def report(m: MessageContainer)(implicit ctx: Context): Unit = - if (!isHidden(m)) { - doReport(m)(ctx.addMode(Mode.Printing)) - m match { - case m: ConditionalWarning if !m.enablingOption.value => - val key = m.enablingOption.name + def report(dia: Diagnostic)(implicit ctx: Context): Unit = + if (!isHidden(dia)) { + doReport(dia)(ctx.addMode(Mode.Printing)) + dia match { + case dia: ConditionalWarning if !dia.enablingOption.value => + val key = dia.enablingOption.name unreportedWarnings = unreportedWarnings.updated(key, unreportedWarnings.getOrElse(key, 0) + 1) - case m: Warning => _warningCount += 1 - case m: Error => - errors = m :: errors + case dia: Warning => _warningCount += 1 + case dia: Error => + errors = dia :: errors _errorCount += 1 - case m: Info => // nothing to do here + case dia: Info => // nothing to do here // match error if d is something else } } - def incomplete(m: MessageContainer)(implicit ctx: Context): Unit = - incompleteHandler(m, ctx) + def incomplete(dia: Diagnostic)(implicit ctx: Context): Unit = + incompleteHandler(dia, ctx) /** Summary of warnings and errors */ def summary: String = { @@ -307,7 +307,7 @@ abstract class Reporter extends interfaces.ReporterResult { } /** Should this diagnostic not be reported at all? */ - def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean = + def isHidden(dia: Diagnostic)(implicit ctx: Context): Boolean = ctx.mode.is(Mode.Printing) /** Does this reporter contain errors that have yet to be reported by its outer reporter ? @@ -316,12 +316,12 @@ abstract class Reporter extends interfaces.ReporterResult { def hasUnreportedErrors: Boolean = false /** If this reporter buffers messages, remove and return all buffered messages. */ - def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] = Nil + def removeBufferedMessages(implicit ctx: Context): List[Diagnostic] = Nil /** Issue all error messages in this reporter to next outer one, or make sure they are written. */ def flush()(implicit ctx: Context): Unit = removeBufferedMessages.foreach(ctx.reporter.report) /** If this reporter buffers messages, all buffered messages, otherwise Nil */ - def pendingMessages(using Context): List[MessageContainer] = Nil + def pendingMessages(using Context): List[Diagnostic] = Nil } diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala index fa5dd6e01138..d633016e69fb 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -5,7 +5,7 @@ package reporting import core.Contexts.Context import collection.mutable import config.Printers.typr -import diagnostic.MessageContainer +import diagnostic.Diagnostic import diagnostic.messages._ /** This class implements a Reporter that stores all messages @@ -20,12 +20,12 @@ import diagnostic.messages._ */ class StoreReporter(outer: Reporter) extends Reporter { - protected var infos: mutable.ListBuffer[MessageContainer] = null + protected var infos: mutable.ListBuffer[Diagnostic] = null - def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { - typr.println(s">>>> StoredError: ${m.message}") // !!! DEBUG + def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = { + typr.println(s">>>> StoredError: ${dia.message}") // !!! DEBUG if (infos == null) infos = new mutable.ListBuffer - infos += m + infos += dia } override def hasUnreportedErrors: Boolean = @@ -34,11 +34,11 @@ class StoreReporter(outer: Reporter) extends Reporter { override def hasStickyErrors: Boolean = infos != null && infos.exists(_.isInstanceOf[StickyError]) - override def removeBufferedMessages(implicit ctx: Context): List[MessageContainer] = + override def removeBufferedMessages(implicit ctx: Context): List[Diagnostic] = if (infos != null) try infos.toList finally infos = null else Nil - override def pendingMessages(using Context): List[MessageContainer] = infos.toList + override def pendingMessages(using Context): List[Diagnostic] = infos.toList override def errorsReported: Boolean = hasErrors || (outer != null && outer.errorsReported) } diff --git a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala index 758cc3733ad1..30453872055d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala @@ -3,7 +3,7 @@ package dotc package reporting import core.Contexts.Context -import diagnostic.MessageContainer +import diagnostic.Diagnostic import diagnostic.messages.Error /** @@ -11,8 +11,8 @@ import diagnostic.messages.Error * info to the underlying reporter. */ class ThrowingReporter(reportInfo: Reporter) extends Reporter { - def doReport(m: MessageContainer)(implicit ctx: Context): Unit = m match { - case _: Error => throw m - case _ => reportInfo.doReport(m) + def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = dia match { + case _: Error => throw dia + case _ => reportInfo.doReport(dia) } } diff --git a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala index 2ed2ce347fcd..ed11aeb3746c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala +++ b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -5,7 +5,7 @@ package reporting import scala.collection.mutable import util.SourceFile import core.Contexts.Context -import diagnostic.MessageContainer +import diagnostic.Diagnostic /** This trait implements `isHidden` so that multiple messages per position * are suppressed, unless they are of increasing severity. */ @@ -16,14 +16,14 @@ trait UniqueMessagePositions extends Reporter { /** Logs a position and returns true if it was already logged. * @note Two positions are considered identical for logging if they have the same point. */ - override def isHidden(m: MessageContainer)(implicit ctx: Context): Boolean = - super.isHidden(m) || { - m.pos.exists && !ctx.settings.YshowSuppressedErrors.value && { + override def isHidden(dia: Diagnostic)(implicit ctx: Context): Boolean = + super.isHidden(dia) || { + dia.pos.exists && !ctx.settings.YshowSuppressedErrors.value && { var shouldHide = false - for (pos <- m.pos.start to m.pos.end) + for (pos <- dia.pos.start to dia.pos.end) positions get (ctx.source, pos) match { - case Some(level) if level >= m.level => shouldHide = true - case _ => positions((ctx.source, pos)) = m.level + case Some(level) if level >= dia.level => shouldHide = true + case _ => positions((ctx.source, pos)) = dia.level } shouldHide } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala similarity index 91% rename from compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala rename to compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala index 0f66f7416a54..f913fd50cb93 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala @@ -8,14 +8,14 @@ import core.Contexts.Context import java.util.Optional -object MessageContainer { +object Diagnostic { val nonSensicalStartTag: String = "" val nonSensicalEndTag: String = "" implicit class MessageContext(val c: Context) extends AnyVal { - def shouldExplain(cont: MessageContainer): Boolean = { + def shouldExplain(dia: Diagnostic): Boolean = { implicit val ctx = c - cont.contained.explanation match { + dia.contained.explanation match { case "" => false case _ => ctx.settings.explain.value } @@ -23,12 +23,12 @@ object MessageContainer { } } -class MessageContainer( +class Diagnostic( val contained: Message, val pos: SourcePosition, val level: Int ) extends Exception with interfaces.Diagnostic { - import MessageContainer._ + import Diagnostic._ private var myMsg: String = null private var myIsNonSensical: Boolean = false private var myContained: Message = null diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala index d30801422749..6a52bf204dae 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala @@ -13,14 +13,14 @@ object Message { * see where old errors still exist */ implicit def toNoExplanation(str: => String): Message = - new NoExplanation(str) + NoExplanation(str) } /** A `Message` contains all semantic information necessary to easily * comprehend what caused the message to be logged. Each message can be turned - * into a `MessageContainer` which contains the log level and can later be + * into a `Diagnostic` which contains the log level and can later be * consumed by a subclass of `Reporter`. However, the error position is only - * part of `MessageContainer`, not `Message`. + * part of `Diagnostic`, not `Message`. * * NOTE: you should not be persisting Most messages take an implicit * `Context` and these contexts weigh in at about 4mb per instance, as such @@ -40,7 +40,7 @@ abstract class Message(val errorId: ErrorMessageID) { self => * > found: Int * * This message will be placed underneath the position given by the enclosing - * `MessageContainer` + * `Diagnostic` */ def msg: String diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 6f0a44ac3107..768a40f0639a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -26,11 +26,11 @@ import printing.Formatting.hl object messages { - // `MessageContainer`s to be consumed by `Reporter` ---------------------- // + // `Diagnostic`s to be consumed by `Reporter` ---------------------- // class Error( msg: Message, pos: SourcePosition - ) extends MessageContainer(msg, pos, ERROR) + ) extends Diagnostic(msg, pos, ERROR) /** A sticky error is an error that should not be hidden by backtracking and * trying some alternative path. Typically, errors issued after catching @@ -44,14 +44,14 @@ object messages { class Warning( msg: Message, pos: SourcePosition - ) extends MessageContainer(msg, pos, WARNING) { + ) extends Diagnostic(msg, pos, WARNING) { def toError: Error = new Error(msg, pos) } class Info( msg: Message, pos: SourcePosition - ) extends MessageContainer(msg, pos, INFO) + ) extends Diagnostic(msg, pos, INFO) abstract class ConditionalWarning( msg: Message, diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index e81370fd894f..28f1c5928f6d 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -7,7 +7,7 @@ import dotc.core.Contexts.Context import dotc.core.StdNames.str import dotc.parsing.Parsers.Parser import dotc.parsing.Tokens -import dotc.reporting.diagnostic.MessageContainer +import dotc.reporting.diagnostic.Diagnostic import dotc.util.SourceFile import scala.annotation.internal.sharable @@ -20,7 +20,7 @@ case class Parsed(source: SourceFile, trees: List[untpd.Tree]) extends ParseResu /** A parsing result containing syntax `errors` */ case class SyntaxErrors(sourceCode: String, - errors: List[MessageContainer], + errors: List[Diagnostic], trees: List[untpd.Tree]) extends ParseResult /** Parsed result is simply a newline */ diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 042baa713fc1..98f27a1530e2 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -16,7 +16,7 @@ import dotty.tools.dotc.core.Symbols.{Symbol, defn} import dotty.tools.dotc.interactive.Completion import dotty.tools.dotc.printing.SyntaxHighlighting import dotty.tools.dotc.reporting.MessageRendering -import dotty.tools.dotc.reporting.diagnostic.{Message, MessageContainer} +import dotty.tools.dotc.reporting.diagnostic.{Message, Diagnostic} import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.util.{SourceFile, SourcePosition} import dotty.tools.dotc.{CompilationUnit, Driver} @@ -380,11 +380,11 @@ class ReplDriver(settings: Array[String], } /** Render messages using the `MessageRendering` trait */ - private def renderMessage(cont: MessageContainer): Context => String = - messageRenderer.messageAndPos(cont.contained, cont.pos, messageRenderer.diagnosticLevel(cont))(_) + private def renderMessage(dia: Diagnostic): Context => String = + messageRenderer.messageAndPos(dia.contained, dia.pos, messageRenderer.diagnosticLevel(dia))(_) /** Output errors to `out` */ - private def displayErrors(errs: Seq[MessageContainer])(implicit state: State): State = { + private def displayErrors(errs: Seq[Diagnostic])(implicit state: State): State = { errs.map(renderMessage(_)(state.context)).foreach(out.println) state } diff --git a/compiler/src/dotty/tools/repl/results.scala b/compiler/src/dotty/tools/repl/results.scala index 28c6fb2fd92a..fed6bab65845 100644 --- a/compiler/src/dotty/tools/repl/results.scala +++ b/compiler/src/dotty/tools/repl/results.scala @@ -1,15 +1,15 @@ package dotty.tools package repl -import dotc.reporting.diagnostic.MessageContainer +import dotc.reporting.diagnostic.Diagnostic /** Contains the different data and type structures used to model results * in the REPL */ object results { - /** Type alias for `List[MessageContainer]` */ - type Errors = List[MessageContainer] + /** Type alias for `List[Diagnostic]` */ + type Errors = List[Diagnostic] /** Result is a type alias for an Either with left value `Errors` */ type Result[+A] = scala.util.Either[Errors, A] diff --git a/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled b/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled index 98e6248184c6..73481b51fe7d 100644 --- a/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled +++ b/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled @@ -6,7 +6,7 @@ import org.junit.Test import org.junit.Assert._ import interfaces.{CompilerCallback, SourceFile} import reporting._ -import reporting.diagnostic.MessageContainer +import reporting.diagnostic.Diagnostic import core.Contexts._ import java.io.File import scala.collection.mutable.ListBuffer @@ -50,7 +50,7 @@ class EntryPointsTest { private class CustomReporter extends Reporter with UniqueMessagePositions with HideNonSensicalMessages { - def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { + def doReport(m: Diagnostic)(implicit ctx: Context): Unit = { } } diff --git a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala index 2fa1944af980..57f9e91245e3 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -5,16 +5,16 @@ package reporting import org.junit.Assert._ import org.junit.Test import core.Contexts._ -import diagnostic.{ErrorMessageID, Message, MessageContainer} +import diagnostic.{ErrorMessageID, Message, Diagnostic} class TestMessageLaziness extends DottyTest { ctx = ctx.fresh.setReporter(new NonchalantReporter) class NonchalantReporter(implicit ctx: Context) extends Reporter with UniqueMessagePositions with HideNonSensicalMessages { - def doReport(m: MessageContainer)(implicit ctx: Context) = ??? + def doReport(dia: Diagnostic)(implicit ctx: Context) = ??? - override def report(m: MessageContainer)(implicit ctx: Context) = () + override def report(dia: Diagnostic)(implicit ctx: Context) = () } case class LazyError() extends Message(ErrorMessageID.LazyErrorId) { diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala index 766844212f06..666589615f13 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala @@ -12,16 +12,16 @@ import scala.collection.mutable import util.SourcePosition import core.Contexts._ import Reporter._ -import diagnostic.{ Message, MessageContainer, NoExplanation } +import diagnostic.{ Message, Diagnostic, NoExplanation } import diagnostic.messages._ import interfaces.Diagnostic.{ ERROR, WARNING, INFO } class TestReporter protected (outWriter: PrintWriter, filePrintln: String => Unit, logLevel: Int) extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering { - import MessageContainer._ + import Diagnostic._ - protected final val _errorBuf = mutable.ArrayBuffer.empty[MessageContainer] - final def errors: Iterator[MessageContainer] = _errorBuf.iterator + protected final val _errorBuf = mutable.ArrayBuffer.empty[Diagnostic] + final def errors: Iterator[Diagnostic] = _errorBuf.iterator protected final val _messageBuf = mutable.ArrayBuffer.empty[String] final def messages: Iterator[String] = _messageBuf.iterator @@ -53,11 +53,11 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M } /** Prints the message with the given position indication. */ - def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = { - val msg = messageAndPos(m.contained, m.pos, diagnosticLevel(m)) - val extraInfo = inlineInfo(m.pos) + def printMessageAndPos(dia: Diagnostic, extra: String)(implicit ctx: Context): Unit = { + val msg = messageAndPos(dia.contained, dia.pos, diagnosticLevel(dia)) + val extraInfo = inlineInfo(dia.pos) - if (m.level >= logLevel) { + if (dia.level >= logLevel) { outWriter.println(msg) if (extraInfo.nonEmpty) outWriter.println(extraInfo) } @@ -66,22 +66,22 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M if (extraInfo.nonEmpty) _messageBuf.append(extraInfo) } - override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { + override def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = { // Here we add extra information that we should know about the error message - val extra = m.contained match { + val extra = dia.contained match { case pm: PatternMatchExhaustivity => s": ${pm.uncovered}" case _ => "" } - m match { - case m: Error => { - _errorBuf.append(m) - _consoleReporter.doReport(m) - printMessageAndPos(m, extra) + dia match { + case dia: Error => { + _errorBuf.append(dia) + _consoleReporter.doReport(dia) + printMessageAndPos(dia, extra) } - case m => - printMessageAndPos(m, extra) + case dia => + printMessageAndPos(dia, extra) } } } @@ -125,10 +125,10 @@ object TestReporter { def simplifiedReporter(writer: PrintWriter): TestReporter = { val rep = new TestReporter(writer, logPrintln, WARNING) { /** Prints the message with the given position indication in a simplified manner */ - override def printMessageAndPos(m: MessageContainer, extra: String)(implicit ctx: Context): Unit = { + override def printMessageAndPos(dia: Diagnostic, extra: String)(implicit ctx: Context): Unit = { def report() = { - val msg = s"${m.pos.line + 1}: " + m.contained.kind + extra - val extraInfo = inlineInfo(m.pos) + val msg = s"${dia.pos.line + 1}: " + dia.contained.kind + extra + val extraInfo = inlineInfo(dia.pos) writer.println(msg) _messageBuf.append(msg) @@ -138,9 +138,9 @@ object TestReporter { _messageBuf.append(extraInfo) } } - m match { - case m: Error => report() - case m: Warning => report() + dia match { + case dia: Error => report() + case dia: Warning => report() case _ => () } } diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index b7436cb32d34..e4b65cd3ba85 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -21,7 +21,7 @@ import dotc.core.Contexts._ import dotc.decompiler import dotc.interfaces.Diagnostic.ERROR import dotc.reporting.{Reporter, TestReporter} -import dotc.reporting.diagnostic.MessageContainer +import dotc.reporting.diagnostic.Diagnostic import dotc.util.DiffUtil import dotty.tools.vulpix.TestConfiguration.defaultOptions @@ -676,7 +676,7 @@ trait ParallelTesting extends RunnerOrchestration { self => (errorMap, expectedErrors) } - def getMissingExpectedErrors(errorMap: HashMap[String, Integer], reporterErrors: Iterator[MessageContainer]) = !reporterErrors.forall { error => + def getMissingExpectedErrors(errorMap: HashMap[String, Integer], reporterErrors: Iterator[Diagnostic]) = !reporterErrors.forall { error => val pos1 = error.pos.nonInlined val key = if (pos1.exists) { def toRelative(path: String): String = // For some reason, absolute paths leak from the compiler itself... diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index d2c1eaea6387..efaedcd70270 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -22,7 +22,7 @@ import core._, core.Decorators._ import Annotations.AnnotInfo import Comments._, Constants._, Contexts._, Flags._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._ import classpath.ClassPathEntries -import reporting._, reporting.diagnostic.{Message, MessageContainer, messages} +import reporting._, reporting.diagnostic.{Message, Diagnostic, messages} import typer.Typer import util.{Set => _, _} import interactive._, interactive.InteractiveDriver._ @@ -689,10 +689,10 @@ object DottyLanguageServer { } yield new lsp4j.Location(uri.toString, r) /** - * Convert a MessageContainer to an lsp4j.Diagnostic. + * Convert a Diagnostic to an lsp4j.Diagnostic. */ - def diagnostic(mc: MessageContainer)(implicit ctx: Context): Option[lsp4j.Diagnostic] = - if (!mc.pos.exists) + def diagnostic(dia: Diagnostic)(implicit ctx: Context): Option[lsp4j.Diagnostic] = + if (!dia.pos.exists) None // diagnostics without positions are not supported: https://github.com/Microsoft/language-server-protocol/issues/249 else { def severity(level: Int): lsp4j.DiagnosticSeverity = { @@ -709,12 +709,12 @@ object DottyLanguageServer { } } - val message = mc.contained - if (displayMessage(message, mc.pos.source)) { + val message = dia.contained + if (displayMessage(message, dia.pos.source)) { val code = message.errorId.errorNumber.toString - range(mc.pos).map(r => + range(dia.pos).map(r => new lsp4j.Diagnostic( - r, mc.message, severity(mc.level), /*source =*/ "", code)) + r, dia.message, severity(dia.level), /*source =*/ "", code)) } else { None } diff --git a/sbt-bridge/src/xsbt/DelegatingReporter.java b/sbt-bridge/src/xsbt/DelegatingReporter.java index 59fd5464bd61..4d3b40e1d7c6 100644 --- a/sbt-bridge/src/xsbt/DelegatingReporter.java +++ b/sbt-bridge/src/xsbt/DelegatingReporter.java @@ -15,11 +15,10 @@ import dotty.tools.dotc.util.SourcePosition; import dotty.tools.dotc.reporting.*; import dotty.tools.dotc.reporting.diagnostic.Message; -import dotty.tools.dotc.reporting.diagnostic.MessageContainer; import dotty.tools.dotc.reporting.diagnostic.messages; import dotty.tools.dotc.core.Contexts.*; -import static dotty.tools.dotc.reporting.diagnostic.MessageContainer.*; +import static dotty.tools.dotc.reporting.diagnostic.Diagnostic.*; final public class DelegatingReporter extends AbstractReporter { private final xsbti.Reporter delegate; @@ -58,7 +57,7 @@ public void printSummary(Context ctx) { delegate.printSummary(); } - public void doReport(MessageContainer cont, Context ctx) { + public void doReport(dotty.tools.dotc.reporting.diagnostic.Diagnostic cont, Context ctx) { Severity severity; switch (cont.level()) { case Diagnostic.ERROR: @@ -127,7 +126,7 @@ public Optional pointerSpace() { Message message = cont.contained(); StringBuilder rendered = new StringBuilder(); rendered.append(messageAndPos(message, cont.pos(), diagnosticLevel(cont), ctx)); - boolean shouldExplain = new MessageContainer.MessageContext(ctx).shouldExplain(cont); + boolean shouldExplain = new dotty.tools.dotc.reporting.diagnostic.Diagnostic.MessageContext(ctx).shouldExplain(cont); if (shouldExplain && !message.explanation().isEmpty()) { rendered.append(explanation(message, ctx)); } diff --git a/tests/run-custom-args/tasty-interpreter/Test.scala b/tests/run-custom-args/tasty-interpreter/Test.scala index 7feff7c01300..4afb98b40f95 100644 --- a/tests/run-custom-args/tasty-interpreter/Test.scala +++ b/tests/run-custom-args/tasty-interpreter/Test.scala @@ -2,7 +2,7 @@ import java.io.{ByteArrayOutputStream, File, PrintStream} import dotty.tools.dotc.core.Contexts import dotty.tools.dotc.reporting.Reporter -import dotty.tools.dotc.reporting.diagnostic.MessageContainer +import dotty.tools.dotc.reporting.diagnostic.Diagnostic import dotty.tools.dotc.util.DiffUtil import dotty.tools.io.Path @@ -78,7 +78,7 @@ object Test { def compileAndInterpret(testFileName: String) = { val reproter = new Reporter { - def doReport(m: MessageContainer)(implicit ctx: Contexts.Context): Unit = println(m) + def doReport(dia: Diagnostic)(implicit ctx: Contexts.Context): Unit = println(dia) } val out = java.nio.file.Paths.get("out/interpreted") if (!java.nio.file.Files.exists(out)) From 850659ca8105c444e064f21763dc31a1544b8099 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 13:20:53 +0100 Subject: [PATCH 07/13] Move Diagnostic subclasses to Diagnostic object --- .../dotc/reporting/ConsoleReporter.scala | 2 +- .../dotc/reporting/MessageRendering.scala | 4 +- .../dotty/tools/dotc/reporting/Reporter.scala | 2 +- .../tools/dotc/reporting/StoreReporter.scala | 2 +- .../dotc/reporting/ThrowingReporter.scala | 2 +- .../reporting/diagnostic/Diagnostic.scala | 67 +++++++++++++- .../dotc/reporting/diagnostic/messages.scala | 89 +++---------------- .../src/dotty/tools/dotc/typer/Inliner.scala | 2 +- .../src/dotty/tools/repl/ReplCompiler.scala | 6 +- .../tools/dotc/reporting/TestReporter.scala | 1 + 10 files changed, 88 insertions(+), 89 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 43eedeef1820..d9a25a2dfc35 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -5,7 +5,7 @@ package reporting import core.Contexts._ import java.io.{ BufferedReader, PrintWriter } import diagnostic.Diagnostic -import diagnostic.messages.{ Error, ConditionalWarning } +import diagnostic.Diagnostic.{ Error, ConditionalWarning } /** * This class implements a Reporter that displays messages on a text console diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 5bcb25f692e7..0facefb88fd9 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -8,8 +8,8 @@ import core.Contexts.Context import core.Decorators._ import printing.Highlighting.{Blue, Red, Yellow} import printing.SyntaxHighlighting -import diagnostic.{ErrorMessageID, Message, Diagnostic} -import diagnostic.messages._ +import diagnostic.{Diagnostic, Message, ErrorMessageID} +import Diagnostic._ import util.SourcePosition import scala.internal.Chars.{ LF, CR, FF, SU } import scala.annotation.switch diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index a0bcc3278a15..5037949be9b3 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -11,7 +11,7 @@ import core.Decorators.PhaseListDecorator import collection.mutable import core.Mode import dotty.tools.dotc.core.Symbols.{Symbol, NoSymbol} -import diagnostic.messages._ +import diagnostic.Diagnostic._ import diagnostic._ import ast.{tpd, Trees} import Message._ diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala index d633016e69fb..b16520be672a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -6,7 +6,7 @@ import core.Contexts.Context import collection.mutable import config.Printers.typr import diagnostic.Diagnostic -import diagnostic.messages._ +import Diagnostic._ /** This class implements a Reporter that stores all messages * diff --git a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala index 30453872055d..4fc2b12be5fd 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala @@ -4,7 +4,7 @@ package reporting import core.Contexts.Context import diagnostic.Diagnostic -import diagnostic.messages.Error +import diagnostic.Diagnostic.Error /** * This class implements a Reporter that throws all errors and sends warnings and other diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala index f913fd50cb93..a44080219ccc 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala @@ -5,10 +5,12 @@ package diagnostic import util.SourcePosition import core.Contexts.Context +import config.Settings.Setting +import interfaces.Diagnostic.{ERROR, INFO, WARNING} import java.util.Optional -object Diagnostic { +object Diagnostic: val nonSensicalStartTag: String = "" val nonSensicalEndTag: String = "" @@ -21,7 +23,68 @@ object Diagnostic { } } } -} + + // `Diagnostics to be consumed by `Reporter` ---------------------- // + class Error( + msg: Message, + pos: SourcePosition + ) extends Diagnostic(msg, pos, ERROR) + + /** A sticky error is an error that should not be hidden by backtracking and + * trying some alternative path. Typically, errors issued after catching + * a TypeError exception are sticky. + */ + class StickyError( + msg: Message, + pos: SourcePosition + ) extends Error(msg, pos) + + class Warning( + msg: Message, + pos: SourcePosition + ) extends Diagnostic(msg, pos, WARNING) { + def toError: Error = new Error(msg, pos) + } + + class Info( + msg: Message, + pos: SourcePosition + ) extends Diagnostic(msg, pos, INFO) + + abstract class ConditionalWarning( + msg: Message, + pos: SourcePosition + ) extends Warning(msg, pos) { + def enablingOption(implicit ctx: Context): Setting[Boolean] + } + + class FeatureWarning( + msg: Message, + pos: SourcePosition + ) extends ConditionalWarning(msg, pos) { + def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.feature + } + + class UncheckedWarning( + msg: Message, + pos: SourcePosition + ) extends ConditionalWarning(msg, pos) { + def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.unchecked + } + + class DeprecationWarning( + msg: Message, + pos: SourcePosition + ) extends ConditionalWarning(msg, pos) { + def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.deprecation + } + + class MigrationWarning( + msg: Message, + pos: SourcePosition + ) extends ConditionalWarning(msg, pos) { + def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.migration + } class Diagnostic( val contained: Message, diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index 768a40f0639a..9e6b10015be7 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -9,8 +9,6 @@ import Decorators._, Symbols._, Names._, NameOps._, Types._, Flags._ import Denotations.SingleDenotation import SymDenotations.SymDenotation import util.SourcePosition -import config.Settings.Setting -import interfaces.Diagnostic.{ERROR, INFO, WARNING} import parsing.Scanners.Token import parsing.Tokens import printing.Highlighting._ @@ -24,82 +22,20 @@ import scala.util.control.NonFatal import StdNames.nme import printing.Formatting.hl +/** Messages + * ======== + * The role of messages is to provide the necessary details for a simple to + * understand diagnostic event. Each message can be turned into a message + * container (one of the above) by calling the appropriate method on them. + * For instance: + * + * ```scala + * EmptyCatchBlock(tree).error(pos) // res: Error + * EmptyCatchBlock(tree).warning(pos) // res: Warning + * ``` + */ object messages { - // `Diagnostic`s to be consumed by `Reporter` ---------------------- // - class Error( - msg: Message, - pos: SourcePosition - ) extends Diagnostic(msg, pos, ERROR) - - /** A sticky error is an error that should not be hidden by backtracking and - * trying some alternative path. Typically, errors issued after catching - * a TypeError exception are sticky. - */ - class StickyError( - msg: Message, - pos: SourcePosition - ) extends Error(msg, pos) - - class Warning( - msg: Message, - pos: SourcePosition - ) extends Diagnostic(msg, pos, WARNING) { - def toError: Error = new Error(msg, pos) - } - - class Info( - msg: Message, - pos: SourcePosition - ) extends Diagnostic(msg, pos, INFO) - - abstract class ConditionalWarning( - msg: Message, - pos: SourcePosition - ) extends Warning(msg, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] - } - - class FeatureWarning( - msg: Message, - pos: SourcePosition - ) extends ConditionalWarning(msg, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.feature - } - - class UncheckedWarning( - msg: Message, - pos: SourcePosition - ) extends ConditionalWarning(msg, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.unchecked - } - - class DeprecationWarning( - msg: Message, - pos: SourcePosition - ) extends ConditionalWarning(msg, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.deprecation - } - - class MigrationWarning( - msg: Message, - pos: SourcePosition - ) extends ConditionalWarning(msg, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.migration - } - - /** Messages - * ======== - * The role of messages is to provide the necessary details for a simple to - * understand diagnostic event. Each message can be turned into a message - * container (one of the above) by calling the appropriate method on them. - * For instance: - * - * ```scala - * EmptyCatchBlock(tree).error(pos) // res: Error - * EmptyCatchBlock(tree).warning(pos) // res: Warning - * ``` - */ import ast.Trees._ import ast.untpd import ast.tpd @@ -110,7 +46,6 @@ object messages { |${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}""" - // Syntax Errors ---------------------------------------------------------- // abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) extends Message(EmptyCatchOrFinallyBlockID) { lazy val explanation: String = { diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 67b568ab6033..221e79a5299e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -222,7 +222,7 @@ object Inliner { } object Intrinsics { - import dotty.tools.dotc.reporting.diagnostic.messages.Error + import dotty.tools.dotc.reporting.diagnostic.Diagnostic.Error private enum ErrorKind: case Parser, Typer diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index b88957844718..4b4ce7ebb6d7 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Names._ import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.reporting.diagnostic.messages +import dotty.tools.dotc.reporting.diagnostic.Diagnostic import dotty.tools.dotc.transform.{PostTyper, Staging} import dotty.tools.dotc.typer.ImportInfo import dotty.tools.dotc.util.Spans._ @@ -248,7 +248,7 @@ class ReplCompiler extends Compiler { if (errorsAllowed) wrap(trees).result else reported.errors case _ => List( - new messages.Error( + new Diagnostic.Error( s"Couldn't parse '$expr' to valid scala", sourceFile.atSpan(Span(0, expr.length)) ) @@ -258,7 +258,7 @@ class ReplCompiler extends Compiler { def unwrapped(tree: tpd.Tree, sourceFile: SourceFile)(implicit ctx: Context): Result[tpd.ValDef] = { def error: Result[tpd.ValDef] = - List(new messages.Error(s"Invalid scala expression", + List(new Diagnostic.Error(s"Invalid scala expression", sourceFile.atSpan(Span(0, sourceFile.content.length)))).errors import tpd._ diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala index 666589615f13..8f312327edcc 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala @@ -14,6 +14,7 @@ import core.Contexts._ import Reporter._ import diagnostic.{ Message, Diagnostic, NoExplanation } import diagnostic.messages._ +import Diagnostic._ import interfaces.Diagnostic.{ ERROR, WARNING, INFO } class TestReporter protected (outWriter: PrintWriter, filePrintln: String => Unit, logLevel: Int) From e2627ac5b946ada5672804d1cfcac16d26f2db46 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 16:38:37 +0100 Subject: [PATCH 08/13] Merge diagnostic package into parent package reporting It was not clear go me that `diagnostic` should be its own package. --- .../src/dotty/tools/dotc/ast/Desugar.scala | 2 +- .../src/dotty/tools/dotc/core/Comments.scala | 2 +- .../src/dotty/tools/dotc/core/Contexts.scala | 1 - .../tools/dotc/core/SymDenotations.scala | 5 +- .../src/dotty/tools/dotc/core/Symbols.scala | 2 +- .../dotty/tools/dotc/core/TypeErrors.scala | 4 +- .../src/dotty/tools/dotc/core/TypeOps.scala | 3 +- .../src/dotty/tools/dotc/core/Types.scala | 3 +- .../core/unpickleScala2/Scala2Unpickler.scala | 2 +- .../dotc/interactive/InteractiveDriver.scala | 2 +- .../tools/dotc/parsing/JavaParsers.scala | 2 +- .../dotty/tools/dotc/parsing/Parsers.scala | 4 +- .../tools/dotc/printing/Formatting.scala | 2 +- .../dotc/reporting/ConsoleReporter.scala | 3 +- .../{diagnostic => }/Diagnostic.scala | 1 - .../{diagnostic => }/ErrorMessageID.scala | 2 +- .../reporting/HideNonSensicalMessages.scala | 1 - .../reporting/{diagnostic => }/Message.scala | 1 - .../dotc/reporting/MessageRendering.scala | 1 - .../dotty/tools/dotc/reporting/Reporter.scala | 3 +- .../tools/dotc/reporting/StoreReporter.scala | 1 - .../dotc/reporting/ThrowingReporter.scala | 3 +- .../reporting/UniqueMessagePositions.scala | 1 - .../reporting/{diagnostic => }/messages.scala | 1 - .../tools/dotc/transform/CheckStatic.scala | 2 +- .../dotc/transform/ElimErasedValueType.scala | 2 +- .../dotty/tools/dotc/transform/Erasure.scala | 2 +- .../tools/dotc/transform/ExpandSAMs.scala | 2 +- .../tools/dotc/transform/PatternMatcher.scala | 2 +- .../tools/dotc/transform/PostTyper.scala | 8 +- .../tools/dotc/transform/ResolveSuper.scala | 2 +- .../dotty/tools/dotc/transform/TailRec.scala | 2 +- .../tools/dotc/transform/TreeChecker.scala | 2 +- .../tools/dotc/transform/TypeTestsCasts.scala | 2 +- .../tools/dotc/transform/patmat/Space.scala | 2 +- .../dotty/tools/dotc/typer/Applications.scala | 7 +- .../src/dotty/tools/dotc/typer/Checking.scala | 4 +- .../src/dotty/tools/dotc/typer/Dynamic.scala | 2 +- .../tools/dotc/typer/ErrorReporting.scala | 4 +- .../dotty/tools/dotc/typer/Implicits.scala | 2 +- .../src/dotty/tools/dotc/typer/Inliner.scala | 2 +- .../src/dotty/tools/dotc/typer/Namer.scala | 2 +- .../dotty/tools/dotc/typer/RefChecks.scala | 6 +- .../dotty/tools/dotc/typer/TypeAssigner.scala | 2 +- .../src/dotty/tools/dotc/typer/Typer.scala | 4 +- .../dotty/tools/dotc/util/Signatures.scala | 2 +- .../src/dotty/tools/repl/ParseResult.scala | 2 +- .../src/dotty/tools/repl/ReplCompiler.scala | 2 +- .../src/dotty/tools/repl/ReplDriver.scala | 2 +- compiler/src/dotty/tools/repl/results.scala | 2 +- .../tools/dotc/EntryPointsTest.scala.disabled | 2 +- .../dotc/reporting/ErrorMessagesTest.scala | 3 - .../dotc/reporting/ErrorMessagesTests.scala | 1862 +++++++++++++++++ .../dotc/reporting/TestMessageLaziness.scala | 1 - .../tools/dotc/reporting/TestReporter.scala | 3 +- .../reporting/UserDefinedErrorMessages.scala | 7 +- .../dotty/tools/vulpix/ParallelTesting.scala | 2 +- .../languageserver/DottyLanguageServer.scala | 2 +- .../languageserver/DiagnosticsTest.scala | 2 +- .../languageserver/util/CodeTester.scala | 2 +- sbt-bridge/src/xsbt/DelegatingReporter.java | 10 +- .../tasty-interpreter/Test.scala | 2 +- tests/run-staging/i7142.scala | 2 +- 63 files changed, 1931 insertions(+), 94 deletions(-) rename compiler/src/dotty/tools/dotc/reporting/{diagnostic => }/Diagnostic.scala (99%) rename compiler/src/dotty/tools/dotc/reporting/{diagnostic => }/ErrorMessageID.scala (99%) rename compiler/src/dotty/tools/dotc/reporting/{diagnostic => }/Message.scala (99%) rename compiler/src/dotty/tools/dotc/reporting/{diagnostic => }/messages.scala (99%) create mode 100644 compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index f84f50aa8a68..d6b69420596b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -10,7 +10,7 @@ import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName} import typer.{FrontEnd, Namer} import util.{Property, SourceFile, SourcePosition} import collection.mutable.ListBuffer -import reporting.diagnostic.messages._ +import reporting.messages._ import reporting.trace import annotation.constructorOnly import printing.Formatting.hl diff --git a/compiler/src/dotty/tools/dotc/core/Comments.scala b/compiler/src/dotty/tools/dotc/core/Comments.scala index bba3f9aef001..24841568a966 100644 --- a/compiler/src/dotty/tools/dotc/core/Comments.scala +++ b/compiler/src/dotty/tools/dotc/core/Comments.scala @@ -9,7 +9,7 @@ import util.Spans._ import util.CommentParsing._ import util.Property.Key import parsing.Parsers.Parser -import reporting.diagnostic.messages.ProperDefinitionNotFound +import reporting.messages.ProperDefinitionNotFound object Comments { val ContextDoc: Key[ContextDocstrings] = new Key[ContextDocstrings] diff --git a/compiler/src/dotty/tools/dotc/core/Contexts.scala b/compiler/src/dotty/tools/dotc/core/Contexts.scala index ea9cd66d53ca..bd0ef825549f 100644 --- a/compiler/src/dotty/tools/dotc/core/Contexts.scala +++ b/compiler/src/dotty/tools/dotc/core/Contexts.scala @@ -21,7 +21,6 @@ import Implicits.ContextualImplicits import config.Settings._ import config.Config import reporting._ -import reporting.diagnostic.Message import io.{AbstractFile, NoAbstractFile, PlainFile, Path} import scala.io.Codec import collection.mutable diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index b1dea9afea95..557d8cbe36d5 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -20,9 +20,8 @@ import util.Stats import java.util.WeakHashMap import scala.util.control.NonFatal import config.Config -import reporting.diagnostic.Message -import reporting.diagnostic.messages.BadSymbolicReference -import reporting.trace +import reporting.{Message, trace} +import reporting.messages.BadSymbolicReference import collection.mutable import transform.TypeUtils._ diff --git a/compiler/src/dotty/tools/dotc/core/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index af6e7d218460..171e151bdfb4 100644 --- a/compiler/src/dotty/tools/dotc/core/Symbols.scala +++ b/compiler/src/dotty/tools/dotc/core/Symbols.scala @@ -23,7 +23,7 @@ import tpd.{Tree, TreeProvider, TreeOps} import ast.TreeTypeMap import Constants.Constant import Variances.{Variance, varianceFromInt} -import reporting.diagnostic.Message +import reporting.Message import collection.mutable import io.AbstractFile import language.implicitConversions diff --git a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala index 053d5c32a80a..22f9cff6684e 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala @@ -10,8 +10,8 @@ import Contexts._ import SymDenotations._ import Denotations._ import Decorators._ -import reporting.diagnostic.{Message, NoExplanation} -import reporting.diagnostic.messages._ +import reporting.{Message, NoExplanation} +import reporting.messages._ import ast.untpd import config.Printers.cyclicErrors diff --git a/compiler/src/dotty/tools/dotc/core/TypeOps.scala b/compiler/src/dotty/tools/dotc/core/TypeOps.scala index 25662025970a..5564157dcb1f 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeOps.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeOps.scala @@ -12,8 +12,7 @@ import Decorators._ import StdNames._ import collection.mutable import ast.tpd._ -import reporting.trace -import reporting.diagnostic.Message +import reporting.{trace, Message} import config.Printers.{gadts, typr} import typer.Applications._ import typer.ProtoTypes._ diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index cfebb6641bb3..255aae365c9f 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -21,7 +21,6 @@ import CheckRealizable._ import Variances.{Variance, varianceFromInt, varianceToInt, setStructuralVariances, Invariant} import util.Stats._ import util.SimpleIdentitySet -import reporting.diagnostic.Message import ast.tpd._ import ast.TreeTypeMap import printing.Texts._ @@ -34,7 +33,7 @@ import annotation.{tailrec, constructorOnly} import language.implicitConversions import scala.util.hashing.{ MurmurHash3 => hashing } import config.Printers.{core, typr} -import reporting.trace +import reporting.{trace, Message} import java.lang.ref.WeakReference import scala.annotation.internal.sharable diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index a644fbaad5e3..d86e0c1490b5 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -28,7 +28,7 @@ import scala.collection.mutable import scala.collection.mutable.ListBuffer import scala.annotation.switch import reporting.trace -import dotty.tools.dotc.reporting.diagnostic.messages.FailureToEliminateExistential +import dotty.tools.dotc.reporting.messages.FailureToEliminateExistential object Scala2Unpickler { diff --git a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala index 44e93c830d8e..14a7075fef65 100644 --- a/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala +++ b/compiler/src/dotty/tools/dotc/interactive/InteractiveDriver.scala @@ -17,7 +17,7 @@ import ast.{Trees, tpd} import core._, core.Decorators._ import Contexts._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._ import classpath._ -import reporting._, reporting.diagnostic.Diagnostic +import reporting._ import util._ /** A Driver subclass designed to be used from IDEs */ diff --git a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala index cbff9f44e16b..420d2e58ac23 100644 --- a/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/JavaParsers.scala @@ -19,7 +19,7 @@ import Symbols._ import ast.Trees._ import Decorators._ import StdNames._ -import dotty.tools.dotc.reporting.diagnostic.messages.IdentifierExpected +import dotty.tools.dotc.reporting.messages.IdentifierExpected import dotty.tools.dotc.util.SourceFile import util.Spans._ import scala.collection.mutable.ListBuffer diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 8072e5a95172..e2b5d1588496 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -30,8 +30,8 @@ import rewrites.Rewrites.{patch, overlapsPatch} object Parsers { import ast.untpd._ - import reporting.diagnostic.Message - import reporting.diagnostic.messages._ + import reporting.Message + import reporting.messages._ case class OpInfo(operand: Tree, operator: Ident, offset: Offset) diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index d0d189f0e212..025eace2e58c 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -6,7 +6,7 @@ import Texts._, Types._, Flags._, Symbols._, Contexts._ import collection.mutable import Decorators._ import scala.util.control.NonFatal -import reporting.diagnostic.Diagnostic +import reporting.Diagnostic import util.DiffUtil import Highlighting._ diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index d9a25a2dfc35..0a0ebad3b69d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -4,8 +4,7 @@ package reporting import core.Contexts._ import java.io.{ BufferedReader, PrintWriter } -import diagnostic.Diagnostic -import diagnostic.Diagnostic.{ Error, ConditionalWarning } +import Diagnostic.{ Error, ConditionalWarning } /** * This class implements a Reporter that displays messages on a text console diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala similarity index 99% rename from compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala rename to compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index a44080219ccc..10558f11182f 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -1,7 +1,6 @@ package dotty.tools package dotc package reporting -package diagnostic import util.SourcePosition import core.Contexts.Context diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala similarity index 99% rename from compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala rename to compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 575342407c8a..94a1ab0fb514 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -1,4 +1,4 @@ -package dotty.tools.dotc.reporting.diagnostic +package dotty.tools.dotc.reporting /** Unique IDs identifying the messages */ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] { diff --git a/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala b/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala index beb2331db1c7..2ed75a1173c3 100644 --- a/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala @@ -3,7 +3,6 @@ package dotc package reporting import core.Contexts.Context -import diagnostic.Diagnostic /** * This trait implements `isHidden` so that we avoid reporting non-sensical messages. diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala similarity index 99% rename from compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala rename to compiler/src/dotty/tools/dotc/reporting/Message.scala index 6a52bf204dae..c9b6abe3f76e 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -1,7 +1,6 @@ package dotty.tools package dotc package reporting -package diagnostic import util.SourcePosition diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index 0facefb88fd9..fe908736938b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -8,7 +8,6 @@ import core.Contexts.Context import core.Decorators._ import printing.Highlighting.{Blue, Red, Yellow} import printing.SyntaxHighlighting -import diagnostic.{Diagnostic, Message, ErrorMessageID} import Diagnostic._ import util.SourcePosition import scala.internal.Chars.{ LF, CR, FF, SU } diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 5037949be9b3..7667f5b37745 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -11,8 +11,7 @@ import core.Decorators.PhaseListDecorator import collection.mutable import core.Mode import dotty.tools.dotc.core.Symbols.{Symbol, NoSymbol} -import diagnostic.Diagnostic._ -import diagnostic._ +import Diagnostic._ import ast.{tpd, Trees} import Message._ import core.Decorators._ diff --git a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala index b16520be672a..cb1e020df7e3 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -5,7 +5,6 @@ package reporting import core.Contexts.Context import collection.mutable import config.Printers.typr -import diagnostic.Diagnostic import Diagnostic._ /** This class implements a Reporter that stores all messages diff --git a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala index 4fc2b12be5fd..6668b0c49fea 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala @@ -3,8 +3,7 @@ package dotc package reporting import core.Contexts.Context -import diagnostic.Diagnostic -import diagnostic.Diagnostic.Error +import Diagnostic.Error /** * This class implements a Reporter that throws all errors and sends warnings and other diff --git a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala index ed11aeb3746c..046af50561c8 100644 --- a/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala +++ b/compiler/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -5,7 +5,6 @@ package reporting import scala.collection.mutable import util.SourceFile import core.Contexts.Context -import diagnostic.Diagnostic /** This trait implements `isHidden` so that multiple messages per position * are suppressed, unless they are of increasing severity. */ diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala similarity index 99% rename from compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala rename to compiler/src/dotty/tools/dotc/reporting/messages.scala index 9e6b10015be7..1e21a1ffcb43 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -1,7 +1,6 @@ package dotty.tools package dotc package reporting -package diagnostic import core._ import Contexts.Context diff --git a/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala b/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala index 00cf1638f602..395527ffd3fe 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckStatic.scala @@ -8,7 +8,7 @@ import Contexts.Context import Symbols._ import dotty.tools.dotc.ast.tpd import Decorators._ -import reporting.diagnostic.messages._ +import reporting.messages._ /** A transformer that check that requirements of Static fields\methods are implemented: * 1. Only objects can have members annotated with `@static` diff --git a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala index 699105fabb24..788e6240a05e 100644 --- a/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala +++ b/compiler/src/dotty/tools/dotc/transform/ElimErasedValueType.scala @@ -7,7 +7,7 @@ import MegaPhase._ import Types._, Contexts._, Flags._, DenotTransformers._ import Symbols._, StdNames._, Trees._ import TypeErasure.ErasedValueType, ValueClasses._ -import reporting.diagnostic.messages.DoubleDefinition +import reporting.messages.DoubleDefinition import NameKinds.SuperAccessorName object ElimErasedValueType { diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index 29434a210e8d..25429b0dc4fc 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -548,7 +548,7 @@ object Erasure { if (sym is Flags.Package) || (sym.isAllOf(Flags.JavaModule) && !ctx.compilationUnit.isJava) then - ctx.error(reporting.diagnostic.messages.JavaSymbolIsNotAValue(sym), tree.sourcePos) + ctx.error(reporting.messages.JavaSymbolIsNotAValue(sym), tree.sourcePos) private def checkNotErased(tree: Tree)(implicit ctx: Context): tree.type = { if (!ctx.mode.is(Mode.Type)) { diff --git a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala index 9f93af68cf02..b053fde4eabc 100644 --- a/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala +++ b/compiler/src/dotty/tools/dotc/transform/ExpandSAMs.scala @@ -6,7 +6,7 @@ import Contexts._, Symbols._, Types._, Flags._, Decorators._, StdNames._, Consta import MegaPhase._ import SymUtils._ import ast.Trees._ -import dotty.tools.dotc.reporting.diagnostic.messages.TypeMismatch +import dotty.tools.dotc.reporting.messages.TypeMismatch import dotty.tools.dotc.util.Spans.Span /** Expand SAM closures that cannot be represented by the JVM as lambdas to anonymous classes. diff --git a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala index 8e5f069cd277..f112d48e5b05 100644 --- a/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala +++ b/compiler/src/dotty/tools/dotc/transform/PatternMatcher.scala @@ -14,7 +14,7 @@ import Flags._, Constants._ import Decorators._ import NameKinds.{PatMatStdBinderName, PatMatAltsName, PatMatResultName} import config.Printers.patmatch -import reporting.diagnostic.messages._ +import reporting.messages._ import dotty.tools.dotc.ast._ import util.Property._ diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 994527cc9c58..584a15cd3553 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -13,7 +13,7 @@ import Decorators._ import Symbols._, SymUtils._ import ContextFunctionResults.annotateContextResults import config.Printers.typr -import reporting.diagnostic.messages._ +import reporting.messages._ object PostTyper { val name: String = "posttyper" @@ -244,10 +244,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase else dropInlines.transform(arg))) else tree - def app1 = + def app1 = // reverse order of transforming args and fun. This way, we get a chance to see other // well-formedness errors before reporting errors in possible inferred type args of fun. - val args1 = transform(app.args) + val args1 = transform(app.args) cpy.Apply(app)(transform(app.fun), args1) methPart(app) match case Select(nu: New, nme.CONSTRUCTOR) if isCheckable(nu) => @@ -258,7 +258,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase case _ => app1 case UnApply(fun, implicits, patterns) => - // Reverse transform order for the same reason as in `app1` above. + // Reverse transform order for the same reason as in `app1` above. val patterns1 = transform(patterns) cpy.UnApply(tree)(transform(fun), transform(implicits), patterns1) case tree: TypeApply => diff --git a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala index 4b84461e23b3..8a90e20e17bb 100644 --- a/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala +++ b/compiler/src/dotty/tools/dotc/transform/ResolveSuper.scala @@ -12,7 +12,7 @@ import DenotTransformers._ import NameOps._ import NameKinds._ import ResolveSuper._ -import reporting.diagnostic.messages.IllegalSuperAccessor +import reporting.messages.IllegalSuperAccessor /** This phase implements super accessors in classes that need them. * diff --git a/compiler/src/dotty/tools/dotc/transform/TailRec.scala b/compiler/src/dotty/tools/dotc/transform/TailRec.scala index 8965da985df2..af2e5818fd8c 100644 --- a/compiler/src/dotty/tools/dotc/transform/TailRec.scala +++ b/compiler/src/dotty/tools/dotc/transform/TailRec.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Flags._ import dotty.tools.dotc.core.NameKinds.{TailLabelName, TailLocalName, TailTempName} import dotty.tools.dotc.core.StdNames.nme import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.reporting.diagnostic.messages.TailrecNotApplicable +import dotty.tools.dotc.reporting.messages.TailrecNotApplicable import dotty.tools.dotc.transform.MegaPhase.MiniPhase import scala.collection.mutable diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 9ec747f41669..86e9996f7401 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -16,7 +16,7 @@ import core.Mode import typer._ import typer.ErrorReporting._ import reporting.ThrowingReporter -import reporting.diagnostic.messages.TypeMismatch +import reporting.messages.TypeMismatch import ast.Trees._ import ast.{tpd, untpd} import scala.internal.Chars._ diff --git a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index a77f892d9c46..c2d759a0db4e 100644 --- a/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/compiler/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -11,7 +11,7 @@ import ValueClasses._ import SymUtils._ import core.Flags._ import util.Spans._ -import reporting.diagnostic.messages.TypeTestAlwaysSucceeds +import reporting.messages.TypeTestAlwaysSucceeds import reporting.trace import config.Printers.{ transforms => debug } diff --git a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala index e52210d2813c..b1710569e931 100644 --- a/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala +++ b/compiler/src/dotty/tools/dotc/transform/patmat/Space.scala @@ -18,7 +18,7 @@ import Applications._ import Inferencing._ import ProtoTypes._ import transform.SymUtils._ -import reporting.diagnostic.messages._ +import reporting.messages._ import reporting.trace import config.Printers.{exhaustivity => debug} import util.SourcePosition diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 2921a52ec134..ee7b69153353 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -28,11 +28,10 @@ import collection.mutable import config.Printers.{overload, typr, unapp} import TypeApplications._ -import reporting.diagnostic.Message -import reporting.diagnostic.messages.{UnexpectedPatternForSummonFrom, NotAMember, MissingIdent, TypeMismatch} -import reporting.trace +import reporting.messages.{UnexpectedPatternForSummonFrom, NotAMember, MissingIdent, TypeMismatch} +import reporting.{trace, Message} import Constants.{Constant, IntTag, LongTag} -import dotty.tools.dotc.reporting.diagnostic.messages.{UnapplyInvalidReturnType, NotAnExtractor, UnapplyInvalidNumberOfArguments} +import dotty.tools.dotc.reporting.messages.{UnapplyInvalidReturnType, NotAnExtractor, UnapplyInvalidNumberOfArguments} import Denotations.SingleDenotation import annotation.{constructorOnly, threadUnsafe} diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 44dd4183cb4f..bee426610d1b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -35,8 +35,8 @@ import transform.patmat.SpaceEngine.isIrrefutableUnapply import collection.mutable -import reporting.diagnostic.Message -import reporting.diagnostic.messages._ +import reporting.Message +import reporting.messages._ import scala.internal.Chars.isOperatorPart object Checking { diff --git a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala index 6d5685e41cb7..b9f3fb8dff9d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Dynamic.scala +++ b/compiler/src/dotty/tools/dotc/typer/Dynamic.scala @@ -15,7 +15,7 @@ import util.Spans._ import core.Symbols._ import core.Definitions import ErrorReporting._ -import dotty.tools.dotc.reporting.diagnostic.messages.ReassignmentToVal +import dotty.tools.dotc.reporting.messages.ReassignmentToVal object Dynamic { def isDynamicMethod(name: Name): Boolean = diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index e3cf5c03e875..02cf69941ab7 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -9,8 +9,8 @@ import Implicits._, Flags._ import util.Spans._ import util.SourcePosition import java.util.regex.Matcher.quoteReplacement -import reporting.diagnostic.Message -import reporting.diagnostic.messages._ +import reporting.Message +import reporting.messages._ object ErrorReporting { diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 9f546dc896ca..69bdf0a89877 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -24,7 +24,7 @@ import StdNames._ import Constants._ import ProtoTypes._ import ErrorReporting._ -import reporting.diagnostic.Message +import reporting.Message import Inferencing.{fullyDefinedType, isFullyDefined} import Trees._ import transform.SymUtils._ diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 221e79a5299e..fe21741080cd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -222,7 +222,7 @@ object Inliner { } object Intrinsics { - import dotty.tools.dotc.reporting.diagnostic.Diagnostic.Error + import dotty.tools.dotc.reporting.Diagnostic.Error private enum ErrorKind: case Parser, Typer diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 88d5de0228bf..41a721e91c0e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -21,7 +21,7 @@ import Inferencing._ import transform.ValueClasses._ import transform.TypeUtils._ import transform.SymUtils._ -import reporting.diagnostic.messages._ +import reporting.messages._ trait NamerContextOps { this: Context => diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 091461980ab2..2098532d69e0 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -21,7 +21,7 @@ import typer.ErrorReporting._ object RefChecks { import tpd._ - import reporting.diagnostic.messages._ + import reporting.messages._ val name: String = "refchecks" @@ -959,8 +959,8 @@ import RefChecks._ class RefChecks extends MiniPhase { thisPhase => import tpd._ - import reporting.diagnostic.messages.ForwardReferenceExtendsOverDefinition - import dotty.tools.dotc.reporting.diagnostic.messages.UnboundPlaceholderParameter + import reporting.messages.ForwardReferenceExtendsOverDefinition + import dotty.tools.dotc.reporting.messages.UnboundPlaceholderParameter override def phaseName: String = RefChecks.name diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index e632279f9609..ad1466330aa2 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -13,7 +13,7 @@ import ast.Trees._ import NameOps._ import ProtoTypes._ import collection.mutable -import reporting.diagnostic.messages._ +import reporting.messages._ import Checking.{checkNoPrivateLeaks, checkNoWildcard} import scala.annotation.threadUnsafe diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index c371844c1f2e..13e0cab8b6ce 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -94,8 +94,8 @@ class Typer extends Namer import Typer._ import tpd.{cpy => _, _} import untpd.cpy - import reporting.diagnostic.Message - import reporting.diagnostic.messages._ + import reporting.Message + import reporting.messages._ /** A temporary data item valid for a single typed ident: * The set of all root import symbols that have been diff --git a/compiler/src/dotty/tools/dotc/util/Signatures.scala b/compiler/src/dotty/tools/dotc/util/Signatures.scala index 26e2bc04871a..89ed336da185 100644 --- a/compiler/src/dotty/tools/dotc/util/Signatures.scala +++ b/compiler/src/dotty/tools/dotc/util/Signatures.scala @@ -9,7 +9,7 @@ import dotty.tools.dotc.core.Flags.Implicit import dotty.tools.dotc.core.Names.TermName import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.core.Types.{ErrorType, MethodType, PolyType} -import dotty.tools.dotc.reporting.diagnostic.messages +import dotty.tools.dotc.reporting.messages import scala.collection.JavaConverters._ diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index 28f1c5928f6d..12cf55354740 100644 --- a/compiler/src/dotty/tools/repl/ParseResult.scala +++ b/compiler/src/dotty/tools/repl/ParseResult.scala @@ -7,7 +7,7 @@ import dotc.core.Contexts.Context import dotc.core.StdNames.str import dotc.parsing.Parsers.Parser import dotc.parsing.Tokens -import dotc.reporting.diagnostic.Diagnostic +import dotc.reporting.Diagnostic import dotc.util.SourceFile import scala.annotation.internal.sharable diff --git a/compiler/src/dotty/tools/repl/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index 4b4ce7ebb6d7..96eb187b2eac 100644 --- a/compiler/src/dotty/tools/repl/ReplCompiler.scala +++ b/compiler/src/dotty/tools/repl/ReplCompiler.scala @@ -11,7 +11,7 @@ import dotty.tools.dotc.core.Names._ import dotty.tools.dotc.core.Phases.Phase import dotty.tools.dotc.core.StdNames._ import dotty.tools.dotc.core.Symbols._ -import dotty.tools.dotc.reporting.diagnostic.Diagnostic +import dotty.tools.dotc.reporting.Diagnostic import dotty.tools.dotc.transform.{PostTyper, Staging} import dotty.tools.dotc.typer.ImportInfo import dotty.tools.dotc.util.Spans._ diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 98f27a1530e2..8ee9730c331a 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -16,7 +16,7 @@ import dotty.tools.dotc.core.Symbols.{Symbol, defn} import dotty.tools.dotc.interactive.Completion import dotty.tools.dotc.printing.SyntaxHighlighting import dotty.tools.dotc.reporting.MessageRendering -import dotty.tools.dotc.reporting.diagnostic.{Message, Diagnostic} +import dotty.tools.dotc.reporting.{Message, Diagnostic} import dotty.tools.dotc.util.Spans.Span import dotty.tools.dotc.util.{SourceFile, SourcePosition} import dotty.tools.dotc.{CompilationUnit, Driver} diff --git a/compiler/src/dotty/tools/repl/results.scala b/compiler/src/dotty/tools/repl/results.scala index fed6bab65845..032159dc910a 100644 --- a/compiler/src/dotty/tools/repl/results.scala +++ b/compiler/src/dotty/tools/repl/results.scala @@ -1,7 +1,7 @@ package dotty.tools package repl -import dotc.reporting.diagnostic.Diagnostic +import dotc.reporting.Diagnostic /** Contains the different data and type structures used to model results * in the REPL diff --git a/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled b/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled index 73481b51fe7d..e759dd1b0b25 100644 --- a/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled +++ b/compiler/test/dotty/tools/dotc/EntryPointsTest.scala.disabled @@ -6,7 +6,7 @@ import org.junit.Test import org.junit.Assert._ import interfaces.{CompilerCallback, SourceFile} import reporting._ -import reporting.diagnostic.Diagnostic +import reporting.Diagnostic import core.Contexts._ import java.io.File import scala.collection.mutable.ListBuffer diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala index 3811af6b298e..b50ac28bbf96 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala @@ -2,11 +2,8 @@ package dotty.tools package dotc package reporting -import diagnostic._ import core.Contexts.Context - import scala.collection.mutable - import org.junit.Assert._ trait ErrorMessagesTest extends DottyTest { diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala new file mode 100644 index 000000000000..f7bbfeccbb86 --- /dev/null +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -0,0 +1,1862 @@ +package dotty.tools +package dotc +package reporting + +import dotty.tools.backend.jvm.GenBCode +import dotty.tools.dotc.core.Contexts.Context +import dotty.tools.dotc.core.Types.WildcardType +import dotty.tools.dotc.parsing.Tokens +import dotty.tools.dotc.reporting.messages._ +import dotty.tools.dotc.transform.{CheckStatic, Erasure, PostTyper, TailRec} +import dotty.tools.dotc.typer.{FrontEnd, RefChecks} +import org.junit.Assert._ +import org.junit.Test + +class ErrorMessagesT ests extends ErrorMessagesTest { + // In the case where there are no errors, we can do "expectNoErrors" in the + // `Report` + @Test def noErrors = + checkMessagesAfter(FrontEnd.name)("""class Foo""") + .expectNoErrors + + @Test def caseClassExtendsEnum = + checkMessagesAfter(RefChecks.name) { + """ + |enum Foo { case A, B } + |case class Bar() extends Foo + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head + val ClassCannotExtendEnum(cls, parent) :: Nil = messages + assertEquals("Bar", cls.name.show) + assertEquals("Foo", parent.name.show) + assertEquals("", cls.owner.name.show) + } + + @Test def typeMismatch = + checkMessagesAfter(FrontEnd.name) { + """ + |object Foo { + | def bar: String = 1 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + val defn = ictx.definitions + + // Assert that we only got one error message + assertMessageCount(1, messages) + + // Pattern match out the expected error + val TypeMismatch(found, expected, _, _) :: Nil = messages + + // The type of the right hand side will actually be the constant 1, + // therefore we check if it "derivesFrom" `IntClass` + assert(found.derivesFrom(defn.IntClass), s"found was: $found") + + // The expected type is `scala.String` which we dealias to + // `java.lang.String` and compare with `=:=` to `defn.StringType` which + // is a type reference to `java.lang.String` + assert(expected.dealias =:= defn.StringType, s"expected was: $expected") + } + + @Test def overridesNothing = + checkMessagesAfter(RefChecks.name) { + """ + |object Foo { + | override def bar: Unit = {} + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverridesNothing(member) :: Nil = messages + assertEquals("bar", member.name.show) + } + + @Test def overridesNothingDifferentSignature = + checkMessagesAfter(RefChecks.name) { + """ + |class Bar { + | def bar(s: String): Unit = {} + | def bar(s: Int): Unit = {} + | final def bar(s: Long): Unit = {} + |} + |object Foo extends Bar { + | override def bar: Unit = {} + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverridesNothingButNameExists(member, sameName) :: Nil = messages + // check expected context data + assertEquals("bar", member.name.show) + assertEquals(3, sameName.size) + assert(sameName.forall(_.symbol.name.show == "bar"), + "at least one method had an unexpected name") + } + + @Test def forwardReference = + checkMessagesAfter(RefChecks.name) { + """ + |object Forward { + | def block = { + | a.toInt + | val b = 2 + | val a = BigDecimal("4") + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val ForwardReferenceExtendsOverDefinition(value, definition) :: Nil = messages + assertEquals("value b", value.show) + assertEquals("value a", definition.show) + } + + @Test def unexpectedToken = + checkMessagesAfter(FrontEnd.name) { + """ + |object Forward { + | def val = "ds" + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val ExpectedTokenButFound(expected, found) :: Nil = messages + assertEquals(Tokens.IDENTIFIER, expected) + assertEquals(Tokens.VAL, found) + } + + @Test def expectedToken = + checkMessagesAfter(FrontEnd.name) { + """ + |object Forward { + | def `val` = "ds" + |} + """.stripMargin + } + .expectNoErrors + + @Test def leftAndRightAssociative = + checkMessagesAfter(FrontEnd.name) { + """ + |object Ops { + | case class I(j: Int) { + | def +-(i: Int) = i + | def +:(i: Int) = i + | } + | val v = I(1) +- I(4) +: I(4) + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc) :: Nil = messages + assertEquals("+-", op1.show) + assertEquals("+:", op2.show) + assertFalse(op2LeftAssoc) + } + + @Test def cantInstantiateAbstract = + checkMessagesAfter(RefChecks.name) { + """ + |object Scope { + | abstract class Concept + | val x = new Concept() + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages + assertEquals("Concept", cls.name.show) + assertFalse("expected class", isTrait) + } + + @Test def cantInstantiateTrait = + checkMessagesAfter(RefChecks.name) { + """ + |object Scope { + | trait Concept + | val x = new Concept() + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages + assertEquals("Concept", cls.name.show) + assertTrue("expected trait", isTrait) + } + + @Test def overloadedMethodNeedsReturnType = + checkMessagesAfter(FrontEnd.name) { + """ + |class Scope() { + | def foo(i: Int) = foo(i.toString) + | def foo(s: String) = s + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages + assertEquals("foo", cycleSym.name.show) + } + + @Test def i1731 = + checkMessagesAfter(FrontEnd.name) { + """ + |case class Foo[T](x: T) + |object Foo { def apply[T]() = Foo(null.asInstanceOf[T]) } + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages + assertEquals("apply", cycleSym.name.show) + } + + @Test def recursiveMethodNeedsReturnType = + checkMessagesAfter(FrontEnd.name) { + """ + |class Scope() { + | def i = i + 5 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages + assertEquals("i", cycleSym.name.show) + } + + @Test def recursiveValueNeedsReturnType = + checkMessagesAfter(FrontEnd.name) { + """ + |class Scope() { + | lazy val i = i + 5 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val RecursiveValueNeedsResultType(cycleSym) :: Nil = messages + assertEquals("i", cycleSym.name.show) + } + + @Test def recursiveValueNeedsReturnType2 = + checkMessagesAfter(FrontEnd.name) { + """ + |class Scope() { + | lazy val i = j + 5 + | lazy val j = i + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val RecursiveValueNeedsResultType(cycleSym) :: Nil = messages + assertEquals("i", cycleSym.name.show) + } + + @Test def cyclicReferenceInvolving = + checkMessagesAfter(FrontEnd.name) { + """ + |class A { + | val x: T = ??? + | type T <: x.type // error: cyclic reference involving value x + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val CyclicReferenceInvolving(denot) :: Nil = messages + assertEquals("value x", denot.show) + } + + @Test def cyclicReferenceInvolving2 = + checkMessagesAfter(FrontEnd.name) { + """ + |class A { + | implicit val x: T = ??? + | type T <: x.type // error: cyclic reference involving value x + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val CyclicReferenceInvolving(denot) :: Nil = messages + assertEquals("value x", denot.show) + } + + @Test def mutualRecursionre_i2001 = + checkMessagesAfter(FrontEnd.name) { + """ + |class A { + | def odd(x: Int) = if (x == 0) false else !even(x-1) + | def even(x: Int) = if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages + assertEquals("odd", cycleSym.name.show) + } + + @Test def mutualRecursion_i2001a = + checkMessagesAfter(FrontEnd.name) { + """ + |class A { + | def odd(x: Int) = if (x == 0) false else !even(x-1) + | def even(x: Int) = { + | def foo = { + | if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type + | } + | false + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages + assertEquals("odd", cycleSym.name.show) + } + + @Test def mutualRecursion_i2001b = + checkMessagesAfter(FrontEnd.name) { + """ + |class A { + | def odd(x: Int) = if (x == 0) false else !even(x-1) + | def even(x: Int) = { + | val foo = { + | if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type + | } + | false + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages + assertEquals("odd", cycleSym.name.show) + } + + @Test def termMemberNeedsResultTypeForImplicitSearch = + checkMessagesAfter(FrontEnd.name) { + """ + |object implicitDefs { + | def foo(implicit x: String) = 1 + | def bar() = { + | implicit val x = foo + | x + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages + assertEquals("x", cycleSym.name.show) + } + + @Test def implicitSearchForcesImplicitRetType_i4709 = + checkMessagesAfter(FrontEnd.name) { + """ + |import scala.language.implicitConversions + | + |class Context + |class ContextBase { def settings = 1 } + | + |class Test { + | implicit def toBase(ctx: Context): ContextBase = ??? + | + | def test(ctx0: Context) = { + | implicit val ctx = { ctx0.settings; ??? } + | } + |} + """.stripMargin + } + .expect{ (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages + assertEquals("ctx", cycleSym.name.show) + } + + @Test def implicitSearchForcesNonImplicitRetTypeOnExplicitImport_i3253 = + checkMessagesAfter(FrontEnd.name) { + """ + |import Test.test + | + |object Test { + | def test = " " * 10 + |} + """.stripMargin + } + .expect{ (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages + assertEquals("test", cycleSym.name.show) + } + + @Test def superQualMustBeParent = + checkMessagesAfter(FrontEnd.name) { + """ + |class A { + | def foo(): Unit = () + |} + | + |class B { + |} + | + |class C extends A { + | super[B].foo + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val SuperQualMustBeParent(qual, cls) :: Nil = messages + + assertEquals("B", qual.show) + assertEquals("class C", cls.show) + } + + @Test def ambiguousImport = + checkMessagesAfter(FrontEnd.name) { + """ + |object A { + | class ToBeImported + |} + |object B { + | class ToBeImported + |} + |class C { + | import A.ToBeImported + | import B.ToBeImported + | + | val value: ToBeImported = ??? + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + import typer.Typer.BindingPrec._ + + assertMessageCount(1, messages) + val AmbiguousImport(name, newPrec, prevPrec, prevCtx) :: Nil = messages + assertEquals("ToBeImported", name.show) + assertEquals(NamedImport, newPrec) + assertEquals(NamedImport, prevPrec) + } + + @Test def methodDoesNotTakeParameters = + checkMessagesAfter(FrontEnd.name) { + """ + |object Scope { + | def foo = () + | foo() + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val msg @ MethodDoesNotTakeParameters(tree) = messages.head + + assertEquals("Scope.foo", tree.show) + assertEquals("method foo", msg.methodSymbol.show) + } + + @Test def methodDoesNotTakeMoreParameters = + checkMessagesAfter(FrontEnd.name) { + """ + |object Scope{ + | def foo(a: Int) = () + | foo(1)("2") + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val msg @ MethodDoesNotTakeParameters(tree) = messages.head + + assertEquals("Scope.foo(1)", tree.show) + assertEquals("method foo", msg.methodSymbol.show) + } + + @Test def ambiugousOverloadWithWildcard = + checkMessagesAfter(FrontEnd.name) { + """object Context { + | trait A { + | def foo(s: String): String + | def foo: String = foo("foo") + | } + | object B extends A { + | def foo(s: String): String = s + | } + | B.foo + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val AmbiguousOverload(tree, List(alt1, alt2), pt: WildcardType) :: Nil = messages + assertEquals("method foo", alt1.show) + assertEquals("(s: String): String", alt1.info.show) + assertEquals("method foo", alt2.show) + } + + @Test def reassignmentToVal = + checkMessagesAfter(FrontEnd.name) { + """ + |class Context { + | val value = 3 + | value = 4 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ReassignmentToVal(name) :: Nil = messages + assertEquals("value", name.show) + } + + @Test def typeDoesNotTakeParameters = + checkMessagesAfter(FrontEnd.name) { + """ + |trait WithOutParams + |class Extending extends WithOutParams[String] + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TypeDoesNotTakeParameters(tpe, params) :: Nil = messages + assertEquals("WithOutParams", tpe.show) + } + + @Test def parameterizedTypeLacksParameters = + checkMessagesAfter(FrontEnd.name) { + """ + |trait WithParams(s: String) + |class Extending extends WithParams + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val ParameterizedTypeLacksArguments(symbol) :: Nil = messages + assertEquals("trait WithParams", symbol.show) + } + + @Test def varValParametersMayNotBeCallByName = + checkMessagesAfter(FrontEnd.name) { + "trait Trait(val noNoNo: => String)" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val VarValParametersMayNotBeCallByName(name, false) :: Nil = messages + assertEquals("noNoNo", name.show) + } + + @Test def missingTypeParameter = + checkMessagesAfter(FrontEnd.name) { + """object Scope { + | val value: List = null + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val MissingTypeParameterFor(tpe) :: Nil = messages + assertEquals("List", tpe.show) + } + + @Test def missingTypeParameterInTypeApp = + checkMessagesAfter(RefChecks.name) { + """object Scope { + | def f[T] = ??? + | val x = f[List] + | val y = f[Either] + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(2, messages) + assertEquals("Missing type parameter for List", messages(1).msg) + assertEquals("Missing type parameters for Either", messages(0).msg) + } + + @Test def doesNotConformToBound = + checkMessagesAfter(RefChecks.name) { + """class WithParam[A <: List[Int]] + |object Scope { + | val value: WithParam[Int] = null + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val DoesNotConformToBound(tpe, which, bound) :: Nil = messages + assertEquals("Int", tpe.show) + assertEquals("upper", which) + assertEquals("List[Int]", bound.show) + } + + @Test def doesNotConformToSelfType = + checkMessagesAfter(RefChecks.name) { + """class Base + |trait BlendItIn { + | this: Base => + |} + |class Blended extends BlendItIn + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val DoesNotConformToSelfType(category, selfType, cls, otherSelf, relation, other) :: Nil = messages + assertEquals("illegal inheritance", category) + assertEquals("Blended", selfType.show) + assertEquals("class Blended", cls.show) + assertEquals("Base", otherSelf.show) + assertEquals("parent", relation) + assertEquals("trait BlendItIn", other.show) + } + + @Test def doesNotConformToSelfTypeCantBeInstantiated = + checkMessagesAfter(RefChecks.name) { + """class Base + |class RequiresBase { self: Base => } + |object Scope { + | val x = new RequiresBase + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val DoesNotConformToSelfTypeCantBeInstantiated(tpe, selfType) :: Nil = messages + assertEquals("RequiresBase", tpe.show) + assertEquals("Base", selfType.show) + } + + @Test def abstractValueMayNotHaveFinalModifier = + checkMessagesAfter(FrontEnd.name) { + """abstract class Foo { + | final val s: String + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val AbstractMemberMayNotHaveModifier(symbol, flags) :: Nil = messages + assertEquals("value s", symbol.show) + assertEquals("final", flags.flagsString) + } + + @Test def typesAndTraitsCantBeImplicit = + checkMessagesAfter(FrontEnd.name) { + """class Foo { + | implicit trait S + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val TypesAndTraitsCantBeImplicit() :: Nil = messages + } + + @Test def onlyClassesCanBeAbstract = + checkMessagesAfter(FrontEnd.name) { + """class Foo { + | abstract val s: String + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val OnlyClassesCanBeAbstract(symbol) :: Nil = messages + assertEquals("value s", symbol.show) + } + + @Test def abstractOverrideOnlyInTraits = + checkMessagesAfter(FrontEnd.name) { + """class Foo { + | abstract override val s: String = "" + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val AbstractOverrideOnlyInTraits(symbol) :: Nil = messages + assertEquals("value s", symbol.show) + } + + @Test def traitMayNotBeFinal = + checkMessagesAfter(FrontEnd.name) { + """final trait Foo""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val TraitsMayNotBeFinal(symbol) :: Nil = messages + assertEquals("trait Foo", symbol.show) + } + + @Test def nativeMemberMayNotHaveImplementation = + checkMessagesAfter(FrontEnd.name) { + """trait Foo { + | @native def foo() = 5 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val NativeMembersMayNotHaveImplementation(symbol) :: Nil = messages + assertEquals("method foo", symbol.show) + } + + @Test def onlyClassesCanHaveDeclaredButUndefinedMembers = + checkMessagesAfter(FrontEnd.name) { + """object Foo { + | def foo(): Int + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val OnlyClassesCanHaveDeclaredButUndefinedMembers(symbol) :: Nil = messages + assertEquals("method foo", symbol.show) + } + + @Test def cannotExtendAnyval = + checkMessagesAfter(FrontEnd.name) { + """trait Foo extends AnyVal""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val CannotExtendAnyVal(symbol) :: Nil = messages + assertEquals("trait Foo", symbol.show) + } + + @Test def cannotHaveSameNameAs = + checkMessagesAfter(RefChecks.name) { + """trait Foo { + | class A + |} + |class B extends Foo { + | class A + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val CannotHaveSameNameAs(symbol, cls, _) :: Nil = messages + assertEquals("class A", symbol.show) + assertEquals("class A", cls.show) + } + + @Test def valueClassesMayNotDefineInner = + checkMessagesAfter(RefChecks.name) { + """class MyValue(i: Int) extends AnyVal { + | class Inner + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassesMayNotDefineInner(valueClass, inner) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + assertEquals("class Inner", inner.show) + } + + @Test def valueClassesMayNotDefineNonParameterField = + checkMessagesAfter(RefChecks.name) { + """class MyValue(i: Int) extends AnyVal { + | val illegal: Int + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassesMayNotDefineNonParameterField(valueClass, field) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + assertEquals("value illegal", field.show) + } + + @Test def valueClassesMayNotDefineASecondaryConstructor = + checkMessagesAfter(RefChecks.name) { + """class MyValue(i: Int) extends AnyVal { + | def this() = this(2) + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassesMayNotDefineASecondaryConstructor(valueClass, constuctor) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + assertEquals("constructor MyValue", constuctor.show) + } + + @Test def valueClassesMayNotContainInitalization = + checkMessagesAfter(RefChecks.name) { + """class MyValue(i: Int) extends AnyVal { + | println("Hallo?") + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassesMayNotContainInitalization(valueClass) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + } + + @Test def valueClassesMayNotBeContained = + checkMessagesAfter(RefChecks.name) { + """class Outer { + | class MyValue(i: Int) extends AnyVal + |} + |""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassesMayNotBeContainted(valueClass) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + } + + @Test def valueClassesMayNotWrapItself = + checkMessagesAfter(RefChecks.name) { + """class MyValue(i: MyValue) extends AnyVal""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassesMayNotWrapItself(valueClass) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + } + + @Test def valueClassParameterMayNotBeVar = + checkMessagesAfter(RefChecks.name) { + """class MyValue(var i: Int) extends AnyVal""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassParameterMayNotBeAVar(valueClass, param) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + assertEquals("variable i", param.show) + } + + @Test def valueClassNeedsOneVal = + checkMessagesAfter(RefChecks.name) { + """class MyValue() extends AnyVal""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassNeedsOneValParam(valueClass) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + } + + @Test def valueClassParameterMayNotBeCallByName = + checkMessagesAfter(RefChecks.name) { + """class MyValue(a: => Int) extends AnyVal""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ValueClassParameterMayNotBeCallByName(valueClass, param) :: Nil = messages + assertEquals("class MyValue", valueClass.show) + assertEquals("value a", param.show) + } + + @Test def onlyCaseClassOrCaseObjectAllowed = + checkMessagesAfter(FrontEnd.name) { + """case Foobar""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val err :: Nil = messages + assertEquals(err, OnlyCaseClassOrCaseObjectAllowed()) + } + + @Test def expectedClassOrObjectDef = + checkMessagesAfter(FrontEnd.name) { + """Foo""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val err :: Nil = messages + assertEquals(err, ExpectedToplevelDef()) + } + + @Test def implicitClassPrimaryConstructorArity = + checkMessagesAfter(FrontEnd.name) { + """ + |object Test { + | implicit class Foo(i: Int, s: String) + |} + """.stripMargin + } + .expect { (itcx, messages) => + implicit val ctx: Context = itcx + assertMessageCount(1, messages) + val err :: Nil = messages + assertEquals(err, ImplicitClassPrimaryConstructorArity()) + } + + @Test def superCallsNotAllowedInline = + checkMessagesAfter(RefChecks.name) { + """ + |class A { + | def foo(): Unit = () + |} + | + |class B extends A { + | inline def bar(): Unit = super.foo() + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val err :: Nil = messages + val SuperCallsNotAllowedInlineable(symbol) = err + assertEquals("method bar", symbol.show) + } + + @Test def wildcardOnTypeArgumentNotAllowedOnNew = + checkMessagesAfter(RefChecks.name) { + """ + |object TyperDemo { + | class Team[A] + | val team = new Team[?] + |}""".stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val err :: Nil = messages + + assertEquals(err, WildcardOnTypeArgumentNotAllowedOnNew()) + } + + @Test def wrongNumberOfParameters = + checkMessagesAfter(RefChecks.name) { + """object NumberOfParams { + | def unary[T](x: T => Unit) = () + | unary((x, y) => ()) + |} """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val err :: Nil = messages + + assertEquals(err, WrongNumberOfParameters(1)) + } + + @Test def duplicatePrivateProtectedQualifier = + checkMessagesAfter(FrontEnd.name) { + """class Test { + | private[Test] protected[this] def foo(): Unit = () + |} """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val err :: Nil = messages + + assertEquals(DuplicatePrivateProtectedQualifier(), err) + } + + @Test def expectedStartOfTopLevelDefinition = + checkMessagesAfter(FrontEnd.name) { + """private Test {}""" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val err :: Nil = messages + + assertEquals(ExpectedStartOfTopLevelDefinition(), err) + } + + @Test def missingReturnTypeWithReturnStatement = + checkMessagesAfter(FrontEnd.name) { + """class BadFunction { + | def bad() = { return "fail" } + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + + val MissingReturnTypeWithReturnStatement(method) :: Nil = messages + assertEquals(method.name.show, "bad") + } + + @Test def noReturnInInline = + checkMessagesAfter(FrontEnd.name) { + """class BadFunction { + | inline def usesReturn: Int = { return 42 } + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + + val NoReturnFromInlineable(method) :: Nil = messages + assertEquals("method usesReturn", method.show) + } + + @Test def returnOutsideMethodDefinition = + checkMessagesAfter(FrontEnd.name) { + """object A { + | return 5 + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ReturnOutsideMethodDefinition(owner) :: Nil = messages + assertEquals("object A", owner.show) + } + + @Test def extendFinalClass = checkMessagesAfter(RefChecks.name) { + """final class A + | + |class B extends A + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ExtendFinalClass(extender, parent) :: Nil = messages + assertEquals(extender.show, "class B") + assertEquals(parent.show, "class A") + } + + @Test def tailrecNotApplicableNeitherPrivateNorFinal = + checkMessagesAfter(TailRec.name) { + """ + |class Foo { + | @scala.annotation.tailrec + | def foo: Unit = foo + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val TailrecNotApplicable(method) :: Nil = messages + assertEquals(method.show, "method foo") + } + + @Test def expectedTypeBoundOrEquals = + checkMessagesAfter(FrontEnd.name) { + """object typedef { + | type asd > Seq + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val ExpectedTypeBoundOrEquals(found) :: Nil = messages + assertEquals(Tokens.IDENTIFIER, found) + } + + @Test def classAndCompanionNameClash = + checkMessagesAfter(RefChecks.name) { + """ + |class T { + | class G + |} + |object T { + | trait G + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val ClassAndCompanionNameClash(cls, other) :: Nil = messages + + assertEquals("class T", cls.owner.show) + assertEquals("class G", cls.show) + assertEquals("object T", other.owner.show) + assertEquals("trait G", other.show) + + } + + @Test def onlyFunctionsCanBeFollowedByUnderscore = + checkMessagesAfter(FrontEnd.name) { + """ + |class T { + | def main(args: Array[String]): Unit = { + | val n = "T" + | val func = n _ + | } + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val OnlyFunctionsCanBeFollowedByUnderscore(tp) :: Nil = messages + assertEquals("String", tp.show) + } + + @Test def missingEmptyArgumentList = + checkMessagesAfter(FrontEnd.name) { + """ + |class Test { + | def greet(): String = "Hello" + | def main(args: Array[String]): Unit = { + | greet + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val MissingEmptyArgumentList(method) :: Nil = messages + assertEquals("method greet", method.show) + } + + @Test def duplicateNamedTypeParameter = + checkMessagesAfter(FrontEnd.name) { + """ + |object Test { + | def f[A, B]() = ??? + | f[A=Any, A=Any]() + | f[B=Any, B=Any]() + |} + | + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(2, messages) + val DuplicateNamedTypeParameter(n2) :: DuplicateNamedTypeParameter(n1) :: Nil = messages + assertEquals("A", n1.show) + assertEquals("B", n2.show) + } + + @Test def undefinedNamedTypeParameter = + checkMessagesAfter(FrontEnd.name) { + """ + |object Test { + | def f[A, B]() = ??? + | f[A=Any, C=Any]() + | f[C=Any, B=Any]() + |} + | + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(2, messages) + val UndefinedNamedTypeParameter(n2, l2) :: UndefinedNamedTypeParameter(n1, l1) :: Nil = messages + val tpParams = List("A", "B") + assertEquals("C", n1.show) + assertEquals(tpParams, l1.map(_.show)) + assertEquals("C", n2.show) + assertEquals(tpParams, l2.map(_.show)) + + } + + @Test def illegalStartOfStatement = + checkMessagesAfter(FrontEnd.name) { + """ + |object Test { + | { with } + | { private ) } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(2, messages) + val errWithModifier :: err :: Nil = messages + + assertEquals(IllegalStartOfStatement(isModifier = false), err) + assertEquals(IllegalStartOfStatement(isModifier = true), errWithModifier) + } + + @Test def traitIsExpected = + checkMessagesAfter(FrontEnd.name) { + """ + |class A + |class B + | + |object Test { + | def main(args: Array[String]): Unit = { + | val a = new A with B + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TraitIsExpected(symbol) :: Nil = messages + assertEquals("class B", symbol.show) + } + + @Test def traitRedefinedFinalMethodFromAnyRef = + checkMessagesAfter(RefChecks.name) { + """ + |trait C { + | def wait (): Unit + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val TraitRedefinedFinalMethodFromAnyRef(method) = messages.head + assertEquals("method wait", method.show) + } + + @Test def packageNameAlreadyDefined = + checkMessagesAfter(FrontEnd.name) { + """ + |package bar { } + |object bar { } + | + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + val PackageNameAlreadyDefined(pkg) = messages.head + assertEquals(pkg.show, "object bar") + } + + @Test def unapplyInvalidNumberOfArguments = + checkMessagesAfter(FrontEnd.name) { + """ + |case class Boo(a: Int, b: String) + | + |object autoTuplingNeg2 { + | val z = Boo(1, "foo") + | + | z match { + | case Boo(a, b, c) => a + | } + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val UnapplyInvalidNumberOfArguments(qual, argTypes) :: Nil = messages + assertEquals("Boo", qual.show) + assertEquals("(class Int, type String)", argTypes.map(_.typeSymbol).mkString("(", ", ", ")")) + } + + @Test def unapplyInvalidReturnType = + checkMessagesAfter("typer") { + """ + |class A(val i: Int) + | + |object A { + | def unapply(a: A): Int = a.i + | def test(a: A) = a match { + | case A() => 1 + | } + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val UnapplyInvalidReturnType(unapplyResult, unapplyName) :: Nil = messages + assertEquals("Int", unapplyResult.show) + assertEquals("unapply", unapplyName.show) + } + + @Test def unapplySeqInvalidReturnType = + checkMessagesAfter("typer") { + """ + |class A(val i: Int) + | + |object A { + | def unapplySeq(a: A): Int = a.i + | def test(a: A) = a match { + | case A() => 1 + | } + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val UnapplyInvalidReturnType(unapplyResult, unapplyName) :: Nil = messages + assertEquals("Int", unapplyResult.show) + assertEquals("unapplySeq", unapplyName.show) + } + + @Test def staticOnlyAllowedInsideObjects = + checkMessagesAfter(CheckStatic.name) { + """ + |class Foo { + | @annotation.static def bar(): Unit = bar() + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + val StaticFieldsOnlyAllowedInObjects(field) = messages.head + assertEquals(field.show, "method bar") + } + + @Test def staticShouldPrecedeNonStatic = + checkMessagesAfter(CheckStatic.name) { + """ + |class Foo + |object Foo { + | val foo = 1 + | @annotation.static val bar = 2 + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + val StaticFieldsShouldPrecedeNonStatic(field, _) = messages.head + assertEquals(field.show, "value bar") + } + + @Test def cyclicInheritance = + checkMessagesAfter(FrontEnd.name) { + "class A extends A" + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val CyclicInheritance(symbol, _) :: Nil = messages + assertEquals("class A", symbol.show) + } + + @Test def missingCompanionForStatic = + checkMessagesAfter(CheckStatic.name) { + """ + |object Foo { + | @annotation.static def bar(): Unit = () + |} + """.stripMargin + }.expect { (itcx, messages) => + implicit val ctx: Context = itcx + val MissingCompanionForStatic(member) = messages.head + assertEquals(member.show, "method bar") + } + + @Test def polymorphicMethodMissingTypeInParent = + checkMessagesAfter(FrontEnd.name) { + """ + |object Test { + | import scala.reflect.Selectable.reflectiveSelectable + | def foo(x: { def get[T](a: T): Int }) = 5 + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + + assertMessageCount(1, messages) + val PolymorphicMethodMissingTypeInParent(rsym, parentSym) = messages.head + assertEquals("method get", rsym.show) + assertEquals("class Object", parentSym.show) + } + + @Test def typeDoubleDeclaration = + checkMessagesAfter(FrontEnd.name) { + """ + |class Foo { + | val a = 1 + | val a = 2 + |} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val DoubleDefinition(symbol, previousSymbol, _) :: Nil = messages + assertEquals(symbol.name.mangledString, "a") + } + + @Test def renameImportTwice = + checkMessagesAfter(PostTyper.name) { + """ + |import java.lang.{Integer => Foo, Integer => Baz} + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val (msg @ ImportRenamedTwice(ident)) :: Nil = messages + assertEquals(ident.show, "Integer") + } + + @Test def tailRecOptimisation = + checkMessagesAfter(FrontEnd.name) { + """ + |import scala.annotation.tailrec + |@tailrec + |object Test { + | @tailrec val a = "" + | @tailrec var b = "" + |} + |@tailrec + |class Test {} + | + """.stripMargin + }.expect{ (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(4, messages) + + val tailRecMessages = messages.map({ case TailrecNotApplicable(sym) => sym.showKind }).toSet + assertEquals(tailRecMessages, Set("variable", "value", "object", "class")) + } + + @Test def notAnExtractor() = + checkMessagesAfter(FrontEnd.name) { + """ + | trait Foo + | object Foo + | object Test { + | def test(foo: Foo) = foo match { + | case Foo(name) => ??? + | } + | } + """.stripMargin + }.expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val NotAnExtractor(tree) = messages.head + assertEquals("Foo", tree.show) + } + + @Test def memberWithSameNameAsStatic() = + checkMessagesAfter(CheckStatic.name) { + """ + |import scala.annotation.static + |class Camp { + | val name = "" + |} + |object Camp { + | @static val name = "" + |} + """.stripMargin + }.expect { (_, messages) => + assertMessageCount(1, messages) + val message = messages.head + assertTrue(message.isInstanceOf[MemberWithSameNameAsStatic]) + assertEquals(message.msg, "Companion classes cannot define members with same name as a @static member") + } + + @Test def companionOfTraitWithMutableStatic() = + checkMessagesAfter(CheckStatic.name) { + """ + | import scala.annotation.static + | trait Test + | object Test { + | @static var myStatic = "" + | } + """.stripMargin + }.expect { (_, messages) => + assertMessageCount(1, messages) + val message = messages.head + assertTrue(message.isInstanceOf[TraitCompanionWithMutableStatic]) + assertEquals( + "Companion of traits cannot define mutable @static fields", + message.msg + ) + } + + @Test def lazyStaticField() = + checkMessagesAfter(CheckStatic.name) { + """ + | import scala.annotation.static + | class Test + | object Test { + | @static lazy val myStatic = "" + | } + """.stripMargin + }.expect { (_, messages) => + assertMessageCount(1, messages) + val message = messages.head + assertTrue(message.isInstanceOf[LazyStaticField]) + assertEquals( + "Lazy @static fields are not supported", + message.msg + ) + } + + @Test def staticOverridingNonStatic() = + checkMessagesAfter(CheckStatic.name) { + """ + | import scala.annotation.static + | trait Foo { + | val foo = "" + | } + | class Test + | object Test extends Foo { + | @static val foo = "" + | } + """.stripMargin + }.expect { (_, messages) => + assertMessageCount(1, messages) + val message = messages.head + assertTrue(message.isInstanceOf[StaticOverridingNonStaticMembers]) + assertEquals( + "@static members cannot override or implement non-static ones", + message.msg + ) + } + + @Test def StableIdentifiers() = + checkMessagesAfter(FrontEnd.name) { + """ + | object Test { + | var x = 2 + | def test = 2 match { + | case `x` => x + 1 + | } + | } + """.stripMargin + }.expect { (_, messages) => + assertMessageCount(1, messages) + val message = messages.head + assertTrue(message.isInstanceOf[StableIdentPattern]) + assertEquals( + "Stable identifier required, but `x` found", + message.msg + ) + } + + @Test def traitParametersUsedAsParentPrefix() = + checkMessagesAfter(RefChecks.name) { + """ + |class Outer { + | trait Inner + | trait Test(val outer: Outer) extends outer.Inner + |} + |""".stripMargin + }.expect { + (ictx, messages) => + implicit val ctx: Context = ictx + val TraitParameterUsedAsParentPrefix(cls) :: Nil = messages + assertEquals("trait Test", cls.show) + assertEquals( + s"${cls.show} cannot extend from a parent that is derived via its own parameters", + messages.head.msg + ) + } + + @Test def unknownNamedEnclosingClassOrObject() = + checkMessagesAfter(RefChecks.name) { + """ + |class TestObject { + | private[doesNotExist] def test: Int = 5 + |} + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val UnknownNamedEnclosingClassOrObject(name) :: Nil = messages + assertEquals("doesNotExist", name.show) + } + + @Test def illegalCyclicTypeReference() = + checkMessagesAfter(RefChecks.name) { + """ + |type X = List[X] + """.stripMargin + } + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val IllegalCyclicTypeReference(sym, where, lastChecked) :: Nil = messages + assertEquals("type X", sym.show) + assertEquals("alias", where) + assertEquals("List[X]", lastChecked.show) + } + + @Test def erasedTypesCanOnlyBeFunctionTypesSuccess() = + checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int) => Int): Int = 1") + .expectNoErrors + + @Test def erasedTypesCanOnlyBeFunctionTypesFailed() = + checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int)): Int = 1") + .expect { (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val ErasedTypesCanOnlyBeFunctionTypes() :: Nil = messages + assertEquals("Types with erased keyword can only be function types `(erased ...) => ...`", messages.head.msg) + } + + @Test def caseClassMissingParamListSuccessful = + checkMessagesAfter(FrontEnd.name) ("case class Test()") + .expectNoErrors + + @Test def caseClassMissingParamListFailed = + checkMessagesAfter(FrontEnd.name) ("case class Test") + .expect { + (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val CaseClassMissingParamList(tpe) :: Nil = messages + assertEquals("A case class must have at least one parameter list", messages.head.msg) + } + + @Test def caseClassMissingNonImplicitParamListSuccessful = + checkMessagesAfter(FrontEnd.name) ("case class Test()(using foo: String)") + .expectNoErrors + + @Test def caseClassMissingNonImplicitParamListFailed = + checkMessagesAfter(FrontEnd.name) ("case class Test(using foo: String)") + .expect { + (ictx, messages) => + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val CaseClassMissingNonImplicitParamList(tpe) :: Nil = messages + assertEquals("A case class must have at least one non-implicit parameter list", messages.head.msg) + } + + @Test def enumMustContainOneCase = + checkMessagesAfter(RefChecks.name) { + """ + |enum Foo { } + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val EnumerationsShouldNotBeEmpty(typeDef) :: Nil = messages + assertEquals("Enumerations must contain at least one case", errorMsg) + assertEquals("Foo", typeDef.name.toString) + } + + @Test def objectsCannotBeAbstract = + checkMessagesAfter(RefChecks.name) { + """ + |abstract object Foo { } + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val AbstractCannotBeUsedForObjects(mdef) :: Nil = messages + assertEquals("abstract modifier cannot be used for objects", errorMsg) + assertEquals("Foo", mdef.name.toString) + } + + @Test def sealedOnObjectsIsRedundant = + checkMessagesAfter(RefChecks.name) { + """ + |sealed object Foo { } + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val ModifierRedundantForObjects(mdef, "sealed") :: Nil = messages + assertEquals("sealed modifier is redundant for objects", errorMsg) + assertEquals("Foo", mdef.name.toString) + } + + @Test def enumAndCaseWithTypesNeedExplicitExtends = + checkMessagesAfter(RefChecks.name) { + """ + |enum E[T,U,V] { + | case C[X,Y,Z](x: X, y: Y, z: Z) + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef, caseDef) :: Nil = messages + assertEquals("explicit extends clause needed because both enum case and enum class have type parameters", errorMsg) + assertEquals("E", enumDef.name.toString) + assertEquals("C", caseDef.name.toString) + } + + @Test def illegalRedefinitionOfStandardKind = + checkMessagesAfter(RefChecks.name) { + """ package scala { + | class Any() + | } + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val IllegalRedefinitionOfStandardKind(kind, name) :: Nil = messages + assertEquals("illegal redefinition of standard class Any", errorMsg) + assertEquals("class", kind) + assertEquals("Any", name.toString) + } + + @Test def unexpectedPatternForSummonFrom = + checkMessagesAfter(RefChecks.name) { + """import compiletime.summonFrom + |inline def a = summonFrom { + | case x => ??? + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val UnexpectedPatternForSummonFrom(x) :: Nil = messages + assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) + assertEquals("x", x.show) + } + + @Test def unexpectedPatternForSummonWithPatternBinder = + checkMessagesAfter(RefChecks.name) { + """import compiletime.summonFrom + |inline def a = summonFrom { + | case x@String => ??? + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val UnexpectedPatternForSummonFrom(x) :: Nil = messages + assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) + assertEquals("given x @ String", x.show) + } + + @Test def typeSplicesInValPatterns = + checkMessagesAfter(RefChecks.name) { + s"""import scala.quoted._ + |object Foo { + | def f(using q: QuoteContext) = { + | val t: Type[Int] = ??? + | val '[ *:[$$t] ] = ??? + | } + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val TypeSpliceInValPattern(x) :: Nil = messages + assertEquals("Type splices cannot be used in val patterns. Consider using `match` instead.", errorMsg) + assertEquals("t", x.show) + } + + @Test def modifierNotAllowedForDefinition = + checkMessagesAfter(RefChecks.name) { + """object Test { + | opaque def o: Int = 3 + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val ModifierNotAllowedForDefinition(x) :: Nil = messages + assertEquals("Modifier `opaque` is not allowed for this definition", errorMsg) + assertEquals("opaque", x.flagsString) + } +} diff --git a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala index 57f9e91245e3..0a053db14ba1 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -5,7 +5,6 @@ package reporting import org.junit.Assert._ import org.junit.Test import core.Contexts._ -import diagnostic.{ErrorMessageID, Message, Diagnostic} class TestMessageLaziness extends DottyTest { ctx = ctx.fresh.setReporter(new NonchalantReporter) diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala index 8f312327edcc..bec27c93c033 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala @@ -12,8 +12,7 @@ import scala.collection.mutable import util.SourcePosition import core.Contexts._ import Reporter._ -import diagnostic.{ Message, Diagnostic, NoExplanation } -import diagnostic.messages._ +import messages._ import Diagnostic._ import interfaces.Diagnostic.{ ERROR, WARNING, INFO } diff --git a/compiler/test/dotty/tools/dotc/reporting/UserDefinedErrorMessages.scala b/compiler/test/dotty/tools/dotc/reporting/UserDefinedErrorMessages.scala index dff8b7d607f5..51d31de5424d 100644 --- a/compiler/test/dotty/tools/dotc/reporting/UserDefinedErrorMessages.scala +++ b/compiler/test/dotty/tools/dotc/reporting/UserDefinedErrorMessages.scala @@ -3,7 +3,7 @@ package dotc package reporting import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.reporting.diagnostic.messages._ +import dotty.tools.dotc.reporting.messages._ import org.junit.Assert._ import org.junit.Test @@ -24,7 +24,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest { |} """.stripMargin }.expect { (itcx, messages) => - import diagnostic.NoExplanation implicit val ctx: Context = itcx assertMessageCount(1, messages) @@ -49,7 +48,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest { |} """.stripMargin }.expect { (itcx, messages) => - import diagnostic.NoExplanation implicit val ctx: Context = itcx assertMessageCount(1, messages) @@ -75,7 +73,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest { |} """.stripMargin }.expect { (itcx, messages) => - import diagnostic.NoExplanation implicit val ctx: Context = itcx assertMessageCount(1, messages) @@ -98,7 +95,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest { |} """.stripMargin }.expect { (itcx, messages) => - import diagnostic.NoExplanation implicit val ctx: Context = itcx assertMessageCount(1, messages) @@ -121,7 +117,6 @@ class UserDefinedErrorMessages extends ErrorMessagesTest { |} """.stripMargin }.expect { (itcx, messages) => - import diagnostic.NoExplanation implicit val ctx: Context = itcx assertMessageCount(1, messages) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index e4b65cd3ba85..22a210689d83 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -21,7 +21,7 @@ import dotc.core.Contexts._ import dotc.decompiler import dotc.interfaces.Diagnostic.ERROR import dotc.reporting.{Reporter, TestReporter} -import dotc.reporting.diagnostic.Diagnostic +import dotc.reporting.Diagnostic import dotc.util.DiffUtil import dotty.tools.vulpix.TestConfiguration.defaultOptions diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index efaedcd70270..b3e24d456b2a 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -22,7 +22,7 @@ import core._, core.Decorators._ import Annotations.AnnotInfo import Comments._, Constants._, Contexts._, Flags._, Names._, NameOps._, Symbols._, SymDenotations._, Trees._, Types._ import classpath.ClassPathEntries -import reporting._, reporting.diagnostic.{Message, Diagnostic, messages} +import reporting._ import typer.Typer import util.{Set => _, _} import interactive._, interactive.InteractiveDriver._ diff --git a/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala b/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala index bc0fe6cb38d3..7419344a304c 100644 --- a/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala +++ b/language-server/test/dotty/tools/languageserver/DiagnosticsTest.scala @@ -2,7 +2,7 @@ package dotty.tools.languageserver import org.junit.Test -import dotty.tools.dotc.reporting.diagnostic.ErrorMessageID._ +import dotty.tools.dotc.reporting.ErrorMessageID._ import dotty.tools.languageserver.util.Code._ import org.eclipse.lsp4j.DiagnosticSeverity._ diff --git a/language-server/test/dotty/tools/languageserver/util/CodeTester.scala b/language-server/test/dotty/tools/languageserver/util/CodeTester.scala index 6dc18dfa5d29..6deaa3254e35 100644 --- a/language-server/test/dotty/tools/languageserver/util/CodeTester.scala +++ b/language-server/test/dotty/tools/languageserver/util/CodeTester.scala @@ -5,7 +5,7 @@ import dotty.tools.languageserver.util.actions._ import dotty.tools.languageserver.util.embedded.CodeMarker import dotty.tools.languageserver.util.server.{TestFile, TestServer} -import dotty.tools.dotc.reporting.diagnostic.ErrorMessageID +import dotty.tools.dotc.reporting.ErrorMessageID import dotty.tools.dotc.util.Signatures.Signature import org.eclipse.lsp4j.{ CompletionItem, CompletionItemKind, DocumentHighlightKind, Diagnostic, DiagnosticSeverity } diff --git a/sbt-bridge/src/xsbt/DelegatingReporter.java b/sbt-bridge/src/xsbt/DelegatingReporter.java index 4d3b40e1d7c6..618e76a08bf0 100644 --- a/sbt-bridge/src/xsbt/DelegatingReporter.java +++ b/sbt-bridge/src/xsbt/DelegatingReporter.java @@ -14,11 +14,11 @@ import dotty.tools.dotc.util.SourceFile; import dotty.tools.dotc.util.SourcePosition; import dotty.tools.dotc.reporting.*; -import dotty.tools.dotc.reporting.diagnostic.Message; -import dotty.tools.dotc.reporting.diagnostic.messages; +import dotty.tools.dotc.reporting.Message; +import dotty.tools.dotc.reporting.messages; import dotty.tools.dotc.core.Contexts.*; -import static dotty.tools.dotc.reporting.diagnostic.Diagnostic.*; +import static dotty.tools.dotc.reporting.Diagnostic.*; final public class DelegatingReporter extends AbstractReporter { private final xsbti.Reporter delegate; @@ -57,7 +57,7 @@ public void printSummary(Context ctx) { delegate.printSummary(); } - public void doReport(dotty.tools.dotc.reporting.diagnostic.Diagnostic cont, Context ctx) { + public void doReport(dotty.tools.dotc.reporting.Diagnostic cont, Context ctx) { Severity severity; switch (cont.level()) { case Diagnostic.ERROR: @@ -126,7 +126,7 @@ public Optional pointerSpace() { Message message = cont.contained(); StringBuilder rendered = new StringBuilder(); rendered.append(messageAndPos(message, cont.pos(), diagnosticLevel(cont), ctx)); - boolean shouldExplain = new dotty.tools.dotc.reporting.diagnostic.Diagnostic.MessageContext(ctx).shouldExplain(cont); + boolean shouldExplain = new dotty.tools.dotc.reporting.Diagnostic.MessageContext(ctx).shouldExplain(cont); if (shouldExplain && !message.explanation().isEmpty()) { rendered.append(explanation(message, ctx)); } diff --git a/tests/run-custom-args/tasty-interpreter/Test.scala b/tests/run-custom-args/tasty-interpreter/Test.scala index 4afb98b40f95..328cbe3a8958 100644 --- a/tests/run-custom-args/tasty-interpreter/Test.scala +++ b/tests/run-custom-args/tasty-interpreter/Test.scala @@ -2,7 +2,7 @@ import java.io.{ByteArrayOutputStream, File, PrintStream} import dotty.tools.dotc.core.Contexts import dotty.tools.dotc.reporting.Reporter -import dotty.tools.dotc.reporting.diagnostic.Diagnostic +import dotty.tools.dotc.reporting.Diagnostic import dotty.tools.dotc.util.DiffUtil import dotty.tools.io.Path diff --git a/tests/run-staging/i7142.scala b/tests/run-staging/i7142.scala index ba30d3e0832c..aca76b331a42 100644 --- a/tests/run-staging/i7142.scala +++ b/tests/run-staging/i7142.scala @@ -7,7 +7,7 @@ object Test { def main(args: Array[String]): Unit = try run {returning('{ { (x: Int) => ${ throwReturn('x) }} apply 0 })} catch { - case ex: dotty.tools.dotc.reporting.diagnostic.messages.Error => + case ex: dotty.tools.dotc.reporting.messages.Error => assert(ex.getMessage == "While expanding a macro, a reference to value x was used outside the scope where it was defined", ex.getMessage) } } From 158653130daaedeff8d83cc6a41a7cb1accd2a2f Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 18:12:51 +0100 Subject: [PATCH 09/13] Better classification of message kinds --- .../dotty/tools/dotc/reporting/messages.scala | 515 ++--- .../dotty/tools/dotc/typer/Applications.scala | 7 +- .../src/dotty/tools/dotc/typer/Typer.scala | 2 +- .../dotc/reporting/ErrorMessagesTests.scala | 1862 ----------------- .../explicit-nulls/i7883.check | 4 +- tests/neg/3559d.check | 2 +- tests/neg/bad-unapplies.check | 4 +- tests/neg/doubleDefinition.check | 40 +- tests/neg/exports.check | 8 +- tests/neg/i5101.check | 2 +- tests/neg/i5433.check | 2 +- tests/neg/i6436.check | 2 +- tests/neg/i6724.check | 2 +- tests/neg/i7359-f.check | 2 +- tests/neg/i8032.check | 2 +- tests/neg/kinds2.check | 2 +- tests/neg/missing-implicit.check | 6 +- tests/neg/missing-implicit1.check | 10 +- tests/neg/mixin-forwarder-clash1.check | 2 +- tests/neg/mixin-forwarder-clash2.check | 2 +- tests/neg/module-class-name.check | 2 +- tests/neg/multi-file-error.check | 4 +- tests/neg/name-hints.check | 36 +- tests/neg/t6124.check | 4 +- tests/run-staging/i7142.scala | 2 +- 25 files changed, 272 insertions(+), 2254 deletions(-) delete mode 100644 compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 1e21a1ffcb43..494d0f6d4f60 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -44,9 +44,40 @@ object messages { em"""|For a full list of restrictions on implicit classes visit |${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}""" + abstract class SyntaxMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Syntax" + + abstract class TypeMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Type" + + abstract class TypeMismatchMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Type Mismatch" + + abstract class NamingMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Naming" + + abstract class DeclarationMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Declaration" + + /** A simple not found message (either for idents, or member selection. + * Messages of this class are sometimes dropped in favor of other, more + * specific messages. + */ + abstract class NotFoundMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Not Found" + def name: Name + + abstract class PatternMatchMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Pattern Match" + + abstract class CyclicMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Cyclic" + + abstract class ReferenceMsg(errorId: ErrorMessageID) extends Message(errorId): + val kind = "Reference" abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) - extends Message(EmptyCatchOrFinallyBlockID) { + extends SyntaxMsg(EmptyCatchOrFinallyBlockID) { lazy val explanation: String = { val tryString = tryBody match { case Block(Nil, untpd.EmptyTree) => "{}" @@ -83,7 +114,6 @@ object messages { class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) { - val kind: String = "Syntax" lazy val msg: String = em"""|The ${hl("catch")} block does not contain a valid expression, try |adding a case like - ${hl("case e: Exception =>")} to the block""" @@ -91,15 +121,13 @@ object messages { class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchAndFinallyBlockID) { - val kind: String = "Syntax" lazy val msg: String = em"""|A ${hl("try")} without ${hl("catch")} or ${hl("finally")} is equivalent to putting |its body in a block; no exceptions are handled.""" } class DeprecatedWithOperator()(implicit ctx: Context) - extends Message(DeprecatedWithOperatorID) { - val kind: String = "Syntax" + extends SyntaxMsg(DeprecatedWithOperatorID) { lazy val msg: String = em"""${hl("with")} as a type operator has been deprecated; use ${hl("&")} instead""" lazy val explanation: String = @@ -109,8 +137,7 @@ object messages { } class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(CaseClassMissingParamListID) { - val kind: String = "Syntax" + extends SyntaxMsg(CaseClassMissingParamListID) { lazy val msg: String = em"""|A ${hl("case class")} must have at least one parameter list""" @@ -121,13 +148,11 @@ object messages { } class AnonymousFunctionMissingParamType(param: untpd.ValDef, - args: List[untpd.Tree], - tree: untpd.Function, - pt: Type) - (implicit ctx: Context) - extends Message(AnonymousFunctionMissingParamTypeID) { - val kind: String = "Type" - + args: List[untpd.Tree], + tree: untpd.Function, + pt: Type) + (implicit ctx: Context) + extends TypeMsg(AnonymousFunctionMissingParamTypeID) { lazy val msg: String = { val ofFun = if (MethodType.syntheticParamNames(args.length + 1) contains param.name) @@ -148,8 +173,7 @@ object messages { } class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) - extends Message(WildcardOnTypeArgumentNotAllowedOnNewID) { - val kind: String = "Syntax" + extends SyntaxMsg(WildcardOnTypeArgumentNotAllowedOnNewID) { lazy val msg: String = "Type argument must be fully defined" lazy val explanation: String = val code1: String = @@ -181,8 +205,7 @@ object messages { // Type Errors ------------------------------------------------------------ // class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) - extends Message(DuplicateBindID) { - val kind: String = "Naming" + extends NamingMsg(DuplicateBindID) { lazy val msg: String = em"duplicate pattern variable: ${bind.name}" lazy val explanation: String = { @@ -208,10 +231,8 @@ object messages { } class MissingIdent(tree: untpd.Ident, treeKind: String, val name: Name)(implicit ctx: Context) - extends Message(MissingIdentID) { - val kind: String = "Unbound Identifier" + extends NotFoundMsg(MissingIdentID) { lazy val msg: String = em"Not found: $treeKind$name" - lazy val explanation: String = { em"""|The identifier for `$treeKind$name` is not bound, that is, |no declaration for this identifier can be found. @@ -221,8 +242,7 @@ object messages { } class TypeMismatch(found: Type, expected: Type, addendum: => String = "")(implicit ctx: Context) - extends Message(TypeMismatchID): - val kind: String = "Type Mismatch" + extends TypeMismatchMsg(TypeMismatchID): // replace constrained TypeParamRefs and their typevars by their bounds where possible // the idea is that if the bounds are also not-subtypes of each other to report @@ -268,9 +288,7 @@ object messages { end TypeMismatch class NotAMember(site: Type, val name: Name, selected: String, addendum: => String = "")(implicit ctx: Context) - extends Message(NotAMemberID) { - val kind: String = "Member Not Found" - + extends NotFoundMsg(NotAMemberID) { //println(i"site = $site, decls = ${site.decls}, source = ${site.widen.typeSymbol.sourceFile}") //DEBUG lazy val msg: String = { @@ -329,8 +347,7 @@ object messages { } class EarlyDefinitionsNotSupported()(implicit ctx: Context) - extends Message(EarlyDefinitionsNotSupportedID) { - val kind: String = "Syntax" + extends SyntaxMsg(EarlyDefinitionsNotSupportedID) { lazy val msg: String = "Early definitions are not supported; use trait parameters instead" lazy val explanation: String = { @@ -375,8 +392,7 @@ object messages { } class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(TopLevelImplicitClassID) { - val kind: String = "Syntax" + extends SyntaxMsg(TopLevelImplicitClassID) { lazy val msg: String = em"""An ${hl("implicit class")} may not be top-level""" lazy val explanation: String = { @@ -406,8 +422,7 @@ object messages { } class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(ImplicitCaseClassID) { - val kind: String = "Syntax" + extends SyntaxMsg(ImplicitCaseClassID) { lazy val msg: String = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" lazy val explanation: String = @@ -419,8 +434,7 @@ object messages { } class ImplicitClassPrimaryConstructorArity()(implicit ctx: Context) - extends Message(ImplicitClassPrimaryConstructorArityID){ - val kind: String = "Syntax" + extends SyntaxMsg(ImplicitClassPrimaryConstructorArityID){ lazy val msg: String = "Implicit classes must accept exactly one primary constructor parameter" lazy val explanation: String = { val example = "implicit class RichDate(date: java.util.Date)" @@ -435,8 +449,7 @@ object messages { } class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) - extends Message(ObjectMayNotHaveSelfTypeID) { - val kind: String = "Syntax" + extends SyntaxMsg(ObjectMayNotHaveSelfTypeID) { lazy val msg: String = em"""${hl("object")}s must not have a self ${hl("type")}""" lazy val explanation: String = { @@ -453,8 +466,7 @@ object messages { } class RepeatedModifier(modifier: String)(implicit ctx:Context) - extends Message(RepeatedModifierID) { - val kind: String = "Syntax" + extends SyntaxMsg(RepeatedModifierID) { lazy val msg: String = em"""Repeated modifier $modifier""" lazy val explanation: String = { @@ -475,8 +487,7 @@ object messages { } class InterpolatedStringError()(implicit ctx:Context) - extends Message(InterpolatedStringErrorID) { - val kind: String = "Syntax" + extends SyntaxMsg(InterpolatedStringErrorID) { lazy val msg: String = "Error in interpolated string: identifier or block expected" lazy val explanation: String = { val code1 = "s\"$new Point(0, 0)\"" @@ -493,8 +504,7 @@ object messages { } class UnboundPlaceholderParameter()(implicit ctx:Context) - extends Message(UnboundPlaceholderParameterID) { - val kind: String = "Syntax" + extends SyntaxMsg(UnboundPlaceholderParameterID) { lazy val msg: String = em"""Unbound placeholder parameter; incorrect use of ${hl("_")}""" lazy val explanation: String = em"""|The ${hl("_")} placeholder syntax was used where it could not be bound. @@ -529,8 +539,7 @@ object messages { } class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) - extends Message(IllegalStartSimpleExprID) { - val kind: String = "Syntax" + extends SyntaxMsg(IllegalStartSimpleExprID) { lazy val msg: String = em"expression expected but ${Red(illegalToken)} found" lazy val explanation: String = { em"""|An expression cannot start with ${Red(illegalToken)}.""" @@ -538,8 +547,7 @@ object messages { } class MissingReturnType()(implicit ctx:Context) - extends Message(MissingReturnTypeID) { - val kind: String = "Syntax" + extends SyntaxMsg(MissingReturnTypeID) { lazy val msg: String = "Missing return type" lazy val explanation: String = em"""|An abstract declaration must have a return type. For example: @@ -550,8 +558,7 @@ object messages { } class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) - extends Message(MissingReturnTypeWithReturnStatementID) { - val kind: String = "Syntax" + extends SyntaxMsg(MissingReturnTypeWithReturnStatementID) { lazy val msg: String = em"$method has a return statement; it needs a result type" lazy val explanation: String = em"""|If a method contains a ${hl("return")} statement, it must have an @@ -561,8 +568,7 @@ object messages { } class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) - extends Message(YieldOrDoExpectedInForComprehensionID) { - val kind: String = "Syntax" + extends SyntaxMsg(YieldOrDoExpectedInForComprehensionID) { lazy val msg: String = em"${hl("yield")} or ${hl("do")} expected" lazy val explanation: String = @@ -595,7 +601,7 @@ object messages { class ProperDefinitionNotFound()(implicit ctx: Context) extends Message(ProperDefinitionNotFoundID) { - val kind: String = "Definition Not Found" + val kind: String = "Doc Comment" lazy val msg: String = em"""Proper definition was not found in ${hl("@usecase")}""" lazy val explanation: String = { @@ -633,8 +639,7 @@ object messages { } class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) - extends Message(ByNameParameterNotSupportedID) { - val kind: String = "Syntax" + extends SyntaxMsg(ByNameParameterNotSupportedID) { lazy val msg: String = em"By-name parameter type ${tpe} not allowed here." lazy val explanation: String = @@ -657,8 +662,7 @@ object messages { } class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) - extends Message(WrongNumberOfTypeArgsID) { - val kind: String = "Syntax" + extends SyntaxMsg(WrongNumberOfTypeArgsID) { private val expectedCount = expectedArgs.length private val actualCount = actual.length @@ -699,8 +703,7 @@ object messages { } class IllegalVariableInPatternAlternative()(implicit ctx: Context) - extends Message(IllegalVariableInPatternAlternativeID) { - val kind: String = "Syntax" + extends SyntaxMsg(IllegalVariableInPatternAlternativeID) { lazy val msg: String = "Variables are not allowed in alternative patterns" lazy val explanation: String = { val varInAlternative = @@ -728,8 +731,7 @@ object messages { } class IdentifierExpected(identifier: String)(implicit ctx: Context) - extends Message(IdentifierExpectedID) { - val kind: String = "Syntax" + extends SyntaxMsg(IdentifierExpectedID) { lazy val msg: String = "identifier expected" lazy val explanation: String = { val wrongIdentifier = em"def foo: $identifier = {...}" @@ -749,8 +751,7 @@ object messages { } class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) - extends Message(AuxConstructorNeedsNonImplicitParameterID) { - val kind: String = "Syntax" + extends SyntaxMsg(AuxConstructorNeedsNonImplicitParameterID) { lazy val msg: String = "Auxiliary constructor needs non-implicit parameter list" lazy val explanation: String = em"""|Only the primary constructor is allowed an ${hl("implicit")} parameter list; @@ -765,8 +766,7 @@ object messages { } class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) - extends Message(IncorrectRepeatedParameterSyntaxID) { - val kind: String = "Syntax" + extends SyntaxMsg(IncorrectRepeatedParameterSyntaxID) { lazy val msg: String = "'*' expected" lazy val explanation: String = em"""|Expected * in ${hl("_*")} operator. @@ -792,8 +792,7 @@ object messages { } class IllegalLiteral()(implicit ctx: Context) - extends Message(IllegalLiteralID) { - val kind: String = "Syntax" + extends SyntaxMsg(IllegalLiteralID) { lazy val msg: String = "Illegal literal" lazy val explanation: String = em"""|Available literals can be divided into several groups: @@ -807,8 +806,7 @@ object messages { } class PatternMatchExhaustivity(uncoveredFn: => String)(implicit ctx: Context) - extends Message(PatternMatchExhaustivityID) { - val kind: String = "Pattern Match Exhaustivity" + extends PatternMatchMsg(PatternMatchExhaustivityID) { lazy val uncovered = uncoveredFn lazy val msg: String = em"""|${hl("match")} may not be exhaustive. @@ -825,8 +823,7 @@ object messages { } class UncheckedTypePattern(msgFn: => String)(implicit ctx: Context) - extends Message(UncheckedTypePatternID) { - val kind: String = "Pattern Match Exhaustivity" + extends PatternMatchMsg(UncheckedTypePatternID) { lazy val msg = msgFn lazy val explanation: String = em"""|Type arguments and type refinements are erased during compile time, thus it's @@ -837,22 +834,19 @@ object messages { } class MatchCaseUnreachable()(implicit ctx: Context) - extends Message(MatchCaseUnreachableID) { - val kind: String = "Match case Unreachable" + extends PatternMatchMsg(MatchCaseUnreachableID) { lazy val msg: String = "Unreachable case" lazy val explanation: String = "" } class MatchCaseOnlyNullWarning()(implicit ctx: Context) - extends Message(MatchCaseOnlyNullWarningID) { - val kind: String = "Only null matched" + extends PatternMatchMsg(MatchCaseOnlyNullWarningID) { lazy val msg: String = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" lazy val explanation: String = "" } class SeqWildcardPatternPos()(implicit ctx: Context) - extends Message(SeqWildcardPatternPosID) { - val kind: String = "Syntax" + extends SyntaxMsg(SeqWildcardPatternPosID) { lazy val msg: String = em"""${hl("_*")} can be used only for last argument""" lazy val explanation: String = { val code = @@ -875,8 +869,7 @@ object messages { } class IllegalStartOfSimplePattern()(implicit ctx: Context) - extends Message(IllegalStartOfSimplePatternID) { - val kind: String = "Syntax" + extends SyntaxMsg(IllegalStartOfSimplePatternID) { lazy val msg: String = "pattern expected" lazy val explanation: String = { val sipCode = @@ -955,15 +948,13 @@ object messages { } class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) - extends Message(PkgDuplicateSymbolID) { - val kind: String = "Duplicate Symbol" + extends NamingMsg(PkgDuplicateSymbolID) { lazy val msg: String = em"Trying to define package with same name as $existing" lazy val explanation: String = "" } class ExistentialTypesNoLongerSupported()(implicit ctx: Context) - extends Message(ExistentialTypesNoLongerSupportedID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExistentialTypesNoLongerSupportedID) { lazy val msg: String = em"""|Existential types are no longer supported - |use a wildcard or dependent type instead""" @@ -985,8 +976,7 @@ object messages { } class UnboundWildcardType()(implicit ctx: Context) - extends Message(UnboundWildcardTypeID) { - val kind: String = "Syntax" + extends SyntaxMsg(UnboundWildcardTypeID) { lazy val msg: String = "Unbound wildcard type" lazy val explanation: String = em"""|The wildcard type syntax (${hl("_")}) was used where it could not be bound. @@ -1029,8 +1019,7 @@ object messages { |""" } - class DanglingThisInPath()(implicit ctx: Context) extends Message(DanglingThisInPathID) { - val kind: String = "Syntax" + class DanglingThisInPath()(implicit ctx: Context) extends SyntaxMsg(DanglingThisInPathID) { lazy val msg: String = em"""Expected an additional member selection after the keyword ${hl("this")}""" lazy val explanation: String = val contextCode: String = @@ -1062,8 +1051,7 @@ object messages { } class OverridesNothing(member: Symbol)(implicit ctx: Context) - extends Message(OverridesNothingID) { - val kind: String = "Reference" + extends DeclarationMsg(OverridesNothingID) { lazy val msg: String = em"""${member} overrides nothing""" lazy val explanation: String = @@ -1074,8 +1062,7 @@ object messages { } class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) - extends Message(OverridesNothingButNameExistsID) { - val kind: String = "Reference" + extends DeclarationMsg(OverridesNothingButNameExistsID) { lazy val msg: String = em"""${member} has a different signature than the overridden declaration""" lazy val explanation: String = val existingDecl: String = existing.map(_.showDcl).mkString(" \n") @@ -1091,8 +1078,7 @@ object messages { } class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) - extends Message(ForwardReferenceExtendsOverDefinitionID) { - val kind: String = "Reference" + extends ReferenceMsg(ForwardReferenceExtendsOverDefinitionID) { lazy val msg: String = em"${definition.name} is a forward reference extending over the definition of ${value.name}" lazy val explanation: String = @@ -1110,8 +1096,7 @@ object messages { } class ExpectedTokenButFound(expected: Token, found: Token)(implicit ctx: Context) - extends Message(ExpectedTokenButFoundID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExpectedTokenButFoundID) { private lazy val foundText = Tokens.showToken(found) @@ -1130,8 +1115,7 @@ object messages { } class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) - extends Message(MixedLeftAndRightAssociativeOpsID) { - val kind: String = "Syntax" + extends SyntaxMsg(MixedLeftAndRightAssociativeOpsID) { lazy val msg: String = val op1Asso: String = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" val op2Asso: String = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" @@ -1165,8 +1149,7 @@ object messages { } class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) - extends Message(CantInstantiateAbstractClassOrTraitID) { - val kind: String = "Usage" + extends TypeMsg(CantInstantiateAbstractClassOrTraitID) { private val traitOrAbstract = if (isTrait) "a trait" else "abstract" lazy val msg: String = em"""${cls.name} is ${traitOrAbstract}; it cannot be instantiated""" lazy val explanation: String = @@ -1183,8 +1166,7 @@ object messages { |""".stripMargin } - class UnreducibleApplication(tycon: Type)(using Context) extends Message(UnreducibleApplicationID): - val kind = "Type" + class UnreducibleApplication(tycon: Type)(using Context) extends TypeMsg(UnreducibleApplicationID): lazy val msg = em"unreducible application of higher-kinded type $tycon to wildcard arguments" lazy val explanation = em"""|An abstract type constructor cannot be applied to wildcard arguments. @@ -1192,8 +1174,7 @@ object messages { |supported in Scala 3.""" class OverloadedOrRecursiveMethodNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) - extends Message(OverloadedOrRecursiveMethodNeedsResultTypeID) { - val kind: String = "Cyclic" + extends CyclicMsg(OverloadedOrRecursiveMethodNeedsResultTypeID) { lazy val msg: String = em"""Overloaded or recursive $cycleSym needs return type""" lazy val explanation: String = em"""Case 1: $cycleSym is overloaded @@ -1207,8 +1188,7 @@ object messages { } class RecursiveValueNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) - extends Message(RecursiveValueNeedsResultTypeID) { - val kind: String = "Cyclic" + extends CyclicMsg(RecursiveValueNeedsResultTypeID) { lazy val msg: String = em"""Recursive $cycleSym needs type""" lazy val explanation: String = em"""The definition of $cycleSym is recursive and you need to specify its type. @@ -1216,8 +1196,7 @@ object messages { } class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) - extends Message(CyclicReferenceInvolvingID) { - val kind: String = "Cyclic" + extends CyclicMsg(CyclicReferenceInvolvingID) { lazy val msg: String = val where = if denot.exists then s" involving $denot" else "" em"Cyclic reference$where" @@ -1229,8 +1208,7 @@ object messages { } class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) - extends Message(CyclicReferenceInvolvingImplicitID) { - val kind: String = "Cyclic" + extends CyclicMsg(CyclicReferenceInvolvingImplicitID) { lazy val msg: String = em"""Cyclic reference involving implicit $cycleSym""" lazy val explanation: String = em"""|$cycleSym is declared as part of a cycle which makes it impossible for the @@ -1241,8 +1219,7 @@ object messages { } class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(implicit ctx: Context) - extends Message(SuperQualMustBeParentID) { - val kind: String = "Reference" + extends ReferenceMsg(SuperQualMustBeParentID) { lazy val msg: String = em"""|$qual does not name a parent of $cls""" lazy val explanation: String = val parents: Seq[String] = (cls.info.parents map (_.typeSymbol.name.show)).sorted @@ -1255,8 +1232,7 @@ object messages { } class VarArgsParamMustComeLast()(implicit ctx: Context) - extends Message(IncorrectRepeatedParameterSyntaxID) { - val kind: String = "Syntax" + extends SyntaxMsg(IncorrectRepeatedParameterSyntaxID) { lazy val msg: String = em"""${hl("varargs")} parameter must come last""" lazy val explanation: String = em"""|The ${hl("varargs")} field must be the last field in the method signature. @@ -1267,7 +1243,7 @@ object messages { import typer.Typer.BindingPrec class AmbiguousImport(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec, prevCtx: Context)(implicit ctx: Context) - extends Message(AmbiguousImportID) { + extends ReferenceMsg(AmbiguousImportID) { /** A string which explains how something was bound; Depending on `prec` this is either * imported by @@ -1287,8 +1263,6 @@ object messages { ex"""$howVisible$qualifier in ${em"${whereFound.owner}"}""" } - val kind: String = "Reference" - lazy val msg: String = i"""|Reference to ${em"$name"} is ambiguous |it is both ${bindingString(newPrec, ctx)} @@ -1306,9 +1280,7 @@ object messages { } class MethodDoesNotTakeParameters(tree: tpd.Tree)(implicit ctx: Context) - extends Message(MethodDoesNotTakeParametersId) { - val kind: String = "Reference" - + extends TypeMsg(MethodDoesNotTakeParametersId) { def methodSymbol: Symbol = tpd.methPart(tree).symbol lazy val msg: String = { @@ -1332,9 +1304,7 @@ object messages { class AmbiguousOverload(tree: tpd.Tree, val alternatives: List[SingleDenotation], pt: Type)( err: Errors)( implicit ctx: Context) - extends Message(AmbiguousOverloadID) { - val kind: String = "Reference" - + extends ReferenceMsg(AmbiguousOverloadID) { private def all = if (alternatives.length == 2) "both" else "all" lazy val msg: String = s"""|Ambiguous overload. The ${err.overloadedAltsStr(alternatives)} @@ -1349,8 +1319,7 @@ object messages { } class ReassignmentToVal(name: Name)(implicit ctx: Context) - extends Message(ReassignmentToValID) { - val kind: String = "Reference" + extends TypeMsg(ReassignmentToValID) { lazy val msg: String = em"""Reassignment to val $name""" lazy val explanation: String = em"""|You can not assign a new value to $name as values can't be changed. @@ -1363,8 +1332,7 @@ object messages { } class TypeDoesNotTakeParameters(tpe: Type, params: List[Trees.Tree[Trees.Untyped]])(implicit ctx: Context) - extends Message(TypeDoesNotTakeParametersID) { - val kind: String = "Reference" + extends TypeMsg(TypeDoesNotTakeParametersID) { lazy val msg: String = em"$tpe does not take type parameters" lazy val explanation: String = val ps = @@ -1376,8 +1344,7 @@ object messages { } class ParameterizedTypeLacksArguments(psym: Symbol)(implicit ctx: Context) - extends Message(ParameterizedTypeLacksArgumentsID) { - val kind: String = "Reference" + extends TypeMsg(ParameterizedTypeLacksArgumentsID) { lazy val msg: String = em"Parameterized $psym lacks argument list" lazy val explanation: String = em"""The $psym is declared with non-implicit parameters, you may not leave @@ -1386,8 +1353,7 @@ object messages { } class VarValParametersMayNotBeCallByName(name: TermName, mutable: Boolean)(implicit ctx: Context) - extends Message(VarValParametersMayNotBeCallByNameID) { - val kind: String = "Syntax" + extends SyntaxMsg(VarValParametersMayNotBeCallByNameID) { def varOrVal = if (mutable) em"${hl("var")}" else em"${hl("val")}" lazy val msg: String = s"$varOrVal parameters may not be call-by-name" lazy val explanation: String = @@ -1401,8 +1367,7 @@ object messages { } class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) - extends Message(MissingTypeParameterForID) { - val kind: String = "Syntax" + extends SyntaxMsg(MissingTypeParameterForID) { lazy val msg: String = if (tpe.derivesFrom(defn.AnyKindClass)) em"${tpe} cannot be used as a value type" else em"Missing type parameter for ${tpe}" @@ -1410,8 +1375,7 @@ object messages { } class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) - extends Message(MissingTypeParameterInTypeAppID) { - val kind: String = "Type Mismatch" + extends TypeMsg(MissingTypeParameterInTypeAppID) { def numParams = tpe.typeParams.length def parameters = if (numParams == 1) "parameter" else "parameters" lazy val msg: String = em"Missing type $parameters for $tpe" @@ -1420,8 +1384,7 @@ object messages { class DoesNotConformToBound(tpe: Type, which: String, bound: Type)( err: Errors)(implicit ctx: Context) - extends Message(DoesNotConformToBoundID) { - val kind: String = "Type Mismatch" + extends TypeMismatchMsg(DoesNotConformToBoundID) { lazy val msg: String = em"Type argument ${tpe} does not conform to $which bound $bound${err.whyNoMatchStr(tpe, bound)}" lazy val explanation: String = "" } @@ -1429,8 +1392,7 @@ object messages { class DoesNotConformToSelfType(category: String, selfType: Type, cls: Symbol, otherSelf: Type, relation: String, other: Symbol)( implicit ctx: Context) - extends Message(DoesNotConformToSelfTypeID) { - val kind: String = "Type Mismatch" + extends TypeMismatchMsg(DoesNotConformToSelfTypeID) { lazy val msg: String = em"""$category: self type $selfType of $cls does not conform to self type $otherSelf |of $relation $other""" lazy val explanation: String = @@ -1444,8 +1406,7 @@ object messages { class DoesNotConformToSelfTypeCantBeInstantiated(tp: Type, selfType: Type)( implicit ctx: Context) - extends Message(DoesNotConformToSelfTypeCantBeInstantiatedID) { - val kind: String = "Type Mismatch" + extends TypeMismatchMsg(DoesNotConformToSelfTypeCantBeInstantiatedID) { lazy val msg: String = em"""$tp does not conform to its self type $selfType; cannot be instantiated""" lazy val explanation: String = em"""To create an instance of $tp it needs to inherit $selfType in some way. @@ -1457,47 +1418,41 @@ object messages { class AbstractMemberMayNotHaveModifier(sym: Symbol, flag: FlagSet)( implicit ctx: Context) - extends Message(AbstractMemberMayNotHaveModifierID) { - val kind: String = "Syntax" + extends SyntaxMsg(AbstractMemberMayNotHaveModifierID) { lazy val msg: String = em"""${hl("abstract")} $sym may not have `${flag.flagsString}` modifier""" lazy val explanation: String = "" } class TopLevelCantBeImplicit(sym: Symbol)( implicit ctx: Context) - extends Message(TopLevelCantBeImplicitID) { - val kind: String = "Syntax" + extends SyntaxMsg(TopLevelCantBeImplicitID) { lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for top-level definitions""" lazy val explanation: String = "" } class TypesAndTraitsCantBeImplicit()(implicit ctx: Context) - extends Message(TypesAndTraitsCantBeImplicitID) { - val kind: String = "Syntax" + extends SyntaxMsg(TypesAndTraitsCantBeImplicitID) { lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for types or traits""" lazy val explanation: String = "" } class OnlyClassesCanBeAbstract(sym: Symbol)( implicit ctx: Context) - extends Message(OnlyClassesCanBeAbstractID) { - val kind: String = "Syntax" + extends SyntaxMsg(OnlyClassesCanBeAbstractID) { lazy val explanation: String = "" lazy val msg: String = em"""${hl("abstract")} modifier can be used only for classes; it should be omitted for abstract members""" } class AbstractOverrideOnlyInTraits(sym: Symbol)( implicit ctx: Context) - extends Message(AbstractOverrideOnlyInTraitsID) { - val kind: String = "Syntax" + extends SyntaxMsg(AbstractOverrideOnlyInTraitsID) { lazy val msg: String = em"""${hl("abstract override")} modifier only allowed for members of traits""" lazy val explanation: String = "" } class TraitsMayNotBeFinal(sym: Symbol)( implicit ctx: Context) - extends Message(TraitsMayNotBeFinalID) { - val kind: String = "Syntax" + extends SyntaxMsg(TraitsMayNotBeFinalID) { lazy val msg: String = em"""$sym may not be ${hl("final")}""" lazy val explanation: String = "A trait can never be final since it is abstract and must be extended to be useful." @@ -1505,16 +1460,14 @@ object messages { class NativeMembersMayNotHaveImplementation(sym: Symbol)( implicit ctx: Context) - extends Message(NativeMembersMayNotHaveImplementationID) { - val kind: String = "Syntax" + extends SyntaxMsg(NativeMembersMayNotHaveImplementationID) { lazy val msg: String = em"""${hl("@native")} members may not have an implementation""" lazy val explanation: String = "" } class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( implicit ctx: Context) - extends Message(OnlyClassesCanHaveDeclaredButUndefinedMembersID) { - val kind: String = "Syntax" + extends SyntaxMsg(OnlyClassesCanHaveDeclaredButUndefinedMembersID) { private def varNote = if (sym.is(Mutable)) "Note that variables need to be initialized to be defined." @@ -1524,8 +1477,7 @@ object messages { } class CannotExtendAnyVal(sym: Symbol)(implicit ctx: Context) - extends Message(CannotExtendAnyValID) { - val kind: String = "Syntax" + extends SyntaxMsg(CannotExtendAnyValID) { lazy val msg: String = em"""$sym cannot extend ${hl("AnyVal")}""" lazy val explanation: String = em"""Only classes (not traits) are allowed to extend ${hl("AnyVal")}, but traits may extend @@ -1535,7 +1487,7 @@ object messages { } class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(implicit ctx: Context) - extends Message(CannotHaveSameNameAsID) { + extends SyntaxMsg(CannotHaveSameNameAsID) { import CannotHaveSameNameAs._ def reasonMessage: String = reason match { case CannotBeOverridden => "class definitions cannot be overridden" @@ -1545,7 +1497,6 @@ object messages { |""".stripMargin } - val kind: String = "Syntax" lazy val msg: String = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage lazy val explanation: String = "" } @@ -1556,100 +1507,86 @@ object messages { } class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotDefineInnerID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotDefineInnerID) { lazy val msg: String = em"""Value classes may not define an inner class""" lazy val explanation: String = "" } class ValueClassesMayNotDefineNonParameterField(valueClass: Symbol, field: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotDefineNonParameterFieldID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotDefineNonParameterFieldID) { lazy val msg: String = em"""Value classes may not define non-parameter field""" lazy val explanation: String = "" } class ValueClassesMayNotDefineASecondaryConstructor(valueClass: Symbol, constructor: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotDefineASecondaryConstructorID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotDefineASecondaryConstructorID) { lazy val msg: String = em"""Value classes may not define a secondary constructor""" lazy val explanation: String = "" } class ValueClassesMayNotContainInitalization(valueClass: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotContainInitalizationID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotContainInitalizationID) { lazy val msg: String = em"""Value classes may not contain initialization statements""" lazy val explanation: String = "" } class ValueClassesMayNotBeAbstract(valueClass: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotBeAbstractID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotBeAbstractID) { lazy val msg: String = em"""Value classes may not be ${hl("abstract")}""" lazy val explanation: String = "" } class ValueClassesMayNotBeContainted(valueClass: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotBeContaintedID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotBeContaintedID) { private def localOrMember = if (valueClass.owner.isTerm) "local class" else "member of another class" lazy val msg: String = s"""Value classes may not be a $localOrMember""" lazy val explanation: String = "" } class ValueClassesMayNotWrapItself(valueClass: Symbol)(implicit ctx: Context) - extends Message(ValueClassesMayNotWrapItselfID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassesMayNotWrapItselfID) { lazy val msg: String = """A value class may not wrap itself""" lazy val explanation: String = "" } class ValueClassParameterMayNotBeAVar(valueClass: Symbol, param: Symbol)(implicit ctx: Context) - extends Message(ValueClassParameterMayNotBeAVarID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassParameterMayNotBeAVarID) { lazy val msg: String = em"""A value class parameter may not be a ${hl("var")}""" lazy val explanation: String = em"""A value class must have exactly one ${hl("val")} parameter.""" } class ValueClassNeedsOneValParam(valueClass: Symbol)(implicit ctx: Context) - extends Message(ValueClassNeedsExactlyOneValParamID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassNeedsExactlyOneValParamID) { lazy val msg: String = em"""Value class needs one ${hl("val")} parameter""" lazy val explanation: String = "" } class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(implicit ctx: Context) - extends Message(ValueClassParameterMayNotBeCallByNameID) { - val kind: String = "Syntax" + extends SyntaxMsg(ValueClassParameterMayNotBeCallByNameID) { lazy val msg: String = s"Value class parameter `${param.name}` may not be call-by-name" lazy val explanation: String = "" } class OnlyCaseClassOrCaseObjectAllowed()(implicit ctx: Context) - extends Message(OnlyCaseClassOrCaseObjectAllowedID) { - val kind: String = "Syntax" + extends SyntaxMsg(OnlyCaseClassOrCaseObjectAllowedID) { lazy val msg: String = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" lazy val explanation: String = "" } class ExpectedToplevelDef()(implicit ctx: Context) - extends Message(ExpectedTopLevelDefID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExpectedTopLevelDefID) { lazy val msg: String = "Expected a toplevel definition" lazy val explanation: String = "" } class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context) - extends Message(SuperCallsNotAllowedInlineableID) { - val kind: String = "Syntax" + extends SyntaxMsg(SuperCallsNotAllowedInlineableID) { lazy val msg: String = em"Super call not allowed in inlineable $symbol" lazy val explanation: String = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." } - class NotAPath(tp: Type, usage: String)(using Context) extends Message(NotAPathID): - val kind: String = "Type" + class NotAPath(tp: Type, usage: String)(using Context) extends TypeMsg(NotAPathID): lazy val msg: String = em"$tp is not a valid $usage, since it is not an immutable path" lazy val explanation: String = i"""An immutable path is @@ -1658,31 +1595,27 @@ object messages { | - a selection of an immutable path with an immutable value.""" class WrongNumberOfParameters(expected: Int)(implicit ctx: Context) - extends Message(WrongNumberOfParametersID) { - val kind: String = "Syntax" + extends SyntaxMsg(WrongNumberOfParametersID) { lazy val msg: String = s"Wrong number of parameters, expected: $expected" lazy val explanation: String = "" } class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) - extends Message(DuplicatePrivateProtectedQualifierID) { - val kind: String = "Syntax" + extends SyntaxMsg(DuplicatePrivateProtectedQualifierID) { lazy val msg: String = "Duplicate private/protected qualifier" lazy val explanation: String = em"It is not allowed to combine `private` and `protected` modifiers even if they are qualified to different scopes" } class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) - extends Message(ExpectedStartOfTopLevelDefinitionID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExpectedStartOfTopLevelDefinitionID) { lazy val msg: String = "Expected start of definition" lazy val explanation: String = em"You have to provide either ${hl("class")}, ${hl("trait")}, ${hl("object")}, or ${hl("enum")} definitions after qualifiers" } class NoReturnFromInlineable(owner: Symbol)(implicit ctx: Context) - extends Message(NoReturnFromInlineableID) { - val kind: String = "Syntax" + extends SyntaxMsg(NoReturnFromInlineableID) { lazy val msg: String = em"No explicit ${hl("return")} allowed from inlineable $owner" lazy val explanation: String = em"""Methods marked with ${hl("inline")} modifier may not use ${hl("return")} statements. @@ -1692,8 +1625,7 @@ object messages { } class ReturnOutsideMethodDefinition(owner: Symbol)(implicit ctx: Context) - extends Message(ReturnOutsideMethodDefinitionID) { - val kind: String = "Syntax" + extends SyntaxMsg(ReturnOutsideMethodDefinitionID) { lazy val msg: String = em"${hl("return")} outside method definition" lazy val explanation: String = em"""You used ${hl("return")} in ${owner}. @@ -1702,16 +1634,14 @@ object messages { } class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) - extends Message(ExtendFinalClassID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExtendFinalClassID) { lazy val msg: String = em"$clazz cannot extend ${hl("final")} $finalClazz" lazy val explanation: String = em"""A class marked with the ${hl("final")} keyword cannot be extended""" } class ExpectedTypeBoundOrEquals(found: Token)(implicit ctx: Context) - extends Message(ExpectedTypeBoundOrEqualsID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExpectedTypeBoundOrEqualsID) { lazy val msg: String = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" lazy val explanation: String = @@ -1728,8 +1658,7 @@ object messages { } class ClassAndCompanionNameClash(cls: Symbol, other: Symbol)(implicit ctx: Context) - extends Message(ClassAndCompanionNameClashID) { - val kind: String = "Naming" + extends NamingMsg(ClassAndCompanionNameClashID) { lazy val msg: String = em"Name clash: both ${cls.owner} and its companion object defines ${cls.name.stripModuleClassSuffix}" lazy val explanation: String = em"""|A ${cls.kindString} and its companion object cannot both define a ${hl("class")}, ${hl("trait")} or ${hl("object")} with the same name: @@ -1738,8 +1667,7 @@ object messages { } class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) - extends Message(TailrecNotApplicableID) { - val kind: String = "Syntax" + extends SyntaxMsg(TailrecNotApplicableID) { lazy val msg: String = { val reason = if (!symbol.is(Method)) em"$symbol isn't a method" @@ -1755,18 +1683,24 @@ object messages { class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol])(implicit ctx: Context) extends Message(FailureToEliminateExistentialID) { val kind: String = "Compatibility" - lazy val msg: String = "Failure to eliminate existential type. Proceed at own risk." - lazy val explanation: String = { + lazy val msg: String = val originalType = ctx.printer.dclsText(boundSyms, "; ").show - em"""original type : $tp forSome ${originalType} + em"""An existential type that came from a Scala-2 classfile cannot be + |mapped accurately to to a Scala-3 equivalent. + |original type : $tp forSome ${originalType} |reduces to : $tp1 - |type used instead: $tp2""" - } + |type used instead: $tp2 + |This choice can cause follow-on type errors or hide type errors. + |Proceed at own risk.""" + lazy val explanation: String = + em"""Existential types in their full generality are no longer supported. + |Scala-3 does applications of class types to wildcard type arguments. + |Other forms of existential types that come from Scala-2 classfiles + |are only approximated in a best-effort way.""" } class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(implicit ctx: Context) - extends Message(OnlyFunctionsCanBeFollowedByUnderscoreID) { - val kind: String = "Syntax" + extends SyntaxMsg(OnlyFunctionsCanBeFollowedByUnderscoreID) { lazy val msg: String = em"Only function types can be followed by ${hl("_")} but the current expression has type $tp" lazy val explanation: String = em"""The syntax ${hl("x _")} is no longer supported if ${hl("x")} is not a function. @@ -1774,8 +1708,7 @@ object messages { } class MissingEmptyArgumentList(method: Symbol)(implicit ctx: Context) - extends Message(MissingEmptyArgumentListID) { - val kind: String = "Syntax" + extends SyntaxMsg(MissingEmptyArgumentListID) { lazy val msg: String = em"$method must be called with ${hl("()")} argument" lazy val explanation: String = { val codeExample = @@ -1792,21 +1725,18 @@ object messages { } class DuplicateNamedTypeParameter(name: Name)(implicit ctx: Context) - extends Message(DuplicateNamedTypeParameterID) { - val kind: String = "Syntax" + extends SyntaxMsg(DuplicateNamedTypeParameterID) { lazy val msg: String = em"Type parameter $name was defined multiple times." lazy val explanation: String = "" } class UndefinedNamedTypeParameter(undefinedName: Name, definedNames: List[Name])(implicit ctx: Context) - extends Message(UndefinedNamedTypeParameterID) { - val kind: String = "Syntax" + extends SyntaxMsg(UndefinedNamedTypeParameterID) { lazy val msg: String = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." lazy val explanation: String = "" } - class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends Message(IllegalStartOfStatementID) { - val kind: String = "Syntax" + class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends SyntaxMsg(IllegalStartOfStatementID) { lazy val msg: String = { val addendum = if (isModifier) ": no modifiers allowed here" else "" "Illegal start of statement" + addendum @@ -1814,8 +1744,7 @@ object messages { lazy val explanation: String = "A statement is either an import, a definition or an expression." } - class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends Message(TraitIsExpectedID) { - val kind: String = "Syntax" + class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends SyntaxMsg(TraitIsExpectedID) { lazy val msg: String = em"$symbol is not a trait" lazy val explanation: String = { val errorCodeExample = @@ -1842,14 +1771,12 @@ object messages { } } - class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends Message(TraitRedefinedFinalMethodFromAnyRefID) { - val kind: String = "Syntax" + class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends SyntaxMsg(TraitRedefinedFinalMethodFromAnyRefID) { lazy val msg: String = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." lazy val explanation: String = "" } - class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends Message(PackageNameAlreadyDefinedID) { - val kind: String = "Naming" + class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends NamingMsg(PackageNameAlreadyDefinedID) { lazy val (where, or) = if pkg.associatedFile == null then ("", "") else (s" in ${pkg.associatedFile}", " or delete the containing class file") @@ -1861,8 +1788,7 @@ object messages { } class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) - extends Message(UnapplyInvalidNumberOfArgumentsID) { - val kind: String = "Syntax" + extends SyntaxMsg(UnapplyInvalidNumberOfArgumentsID) { lazy val msg: String = em"Wrong number of argument patterns for $qual; expected: ($argTypes%, %)" lazy val explanation: String = em"""The Unapply method of $qual was used with incorrect number of arguments. @@ -1874,8 +1800,7 @@ object messages { } class UnapplyInvalidReturnType(unapplyResult: Type, unapplyName: Symbol#ThisName)(implicit ctx: Context) - extends Message(UnapplyInvalidReturnTypeID) { - val kind = "Type Mismatch" + extends DeclarationMsg(UnapplyInvalidReturnTypeID) { lazy val msg = val addendum = if (ctx.scala2CompatMode && unapplyName == nme.unapplySeq) @@ -1929,15 +1854,13 @@ object messages { """.stripMargin } - class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends Message(StaticFieldsOnlyAllowedInObjectsID) { - val kind: String = "Syntax" + class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends SyntaxMsg(StaticFieldsOnlyAllowedInObjectsID) { lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}." lazy val explanation: String = em"${hl("@static")} members are only allowed inside objects." } - class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends Message(StaticFieldsShouldPrecedeNonStaticID) { - val kind: String = "Syntax" + class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends SyntaxMsg(StaticFieldsShouldPrecedeNonStaticID) { lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined before non-static fields." lazy val explanation: String = { val nonStatics = defns.takeWhile(_.symbol != member).take(3).filter(_.isInstanceOf[tpd.ValDef]) @@ -1957,8 +1880,7 @@ object messages { } } - class CyclicInheritance(symbol: Symbol, addendum: => String)(implicit ctx: Context) extends Message(CyclicInheritanceID) { - val kind: String = "Syntax" + class CyclicInheritance(symbol: Symbol, addendum: => String)(implicit ctx: Context) extends SyntaxMsg(CyclicInheritanceID) { lazy val msg: String = em"Cyclic inheritance: $symbol extends itself$addendum" lazy val explanation: String = { val codeExample = "class A extends A" @@ -1974,9 +1896,8 @@ object messages { } } - class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) extends Message(BadSymbolicReferenceID) { - val kind: String = "Reference" - + class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) + extends ReferenceMsg(BadSymbolicReferenceID) { lazy val msg: String = { val denotationOwner = denot.owner val denotationName = ctx.fresh.setSetting(ctx.settings.YdebugNames, true).printer.nameString(denot.name) @@ -1994,15 +1915,13 @@ object messages { lazy val explanation: String = "" } - class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends Message(UnableToExtendSealedClassID) { - val kind: String = "Syntax" + class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends SyntaxMsg(UnableToExtendSealedClassID) { lazy val msg: String = em"Cannot extend ${hl("sealed")} $pclazz in a different source file" lazy val explanation: String = "A sealed class or trait can only be extended in the same file as its declaration" } class SymbolHasUnparsableVersionNumber(symbol: Symbol, migrationMessage: => String)(implicit ctx: Context) - extends Message(SymbolHasUnparsableVersionNumberID) { - val kind: String = "Syntax" + extends SyntaxMsg(SymbolHasUnparsableVersionNumberID) { lazy val msg: String = em"${symbol.showLocated} has an unparsable version number: $migrationMessage" lazy val explanation: String = em"""$migrationMessage @@ -2015,8 +1934,7 @@ object messages { class SymbolChangedSemanticsInVersion( symbol: Symbol, migrationVersion: ScalaVersion - )(implicit ctx: Context) extends Message(SymbolChangedSemanticsInVersionID) { - val kind: String = "Syntax" + )(implicit ctx: Context) extends SyntaxMsg(SymbolChangedSemanticsInVersionID) { lazy val msg: String = em"${symbol.showLocated} has changed semantics in version $migrationVersion" lazy val explanation: String = { em"""The ${symbol.showLocated} is marked with ${hl("@migration")} indicating it has changed semantics @@ -2026,8 +1944,7 @@ object messages { } class UnableToEmitSwitch(tooFewCases: Boolean)(implicit ctx: Context) - extends Message(UnableToEmitSwitchID) { - val kind: String = "Syntax" + extends SyntaxMsg(UnableToEmitSwitchID) { def tooFewStr: String = if (tooFewCases) " since there are not enough cases" else "" lazy val msg: String = em"Could not emit switch for ${hl("@switch")} annotated match$tooFewStr" lazy val explanation: String = { @@ -2055,16 +1972,15 @@ object messages { } } - class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) extends Message(MissingCompanionForStaticID) { - val kind: String = "Syntax" + class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) + extends SyntaxMsg(MissingCompanionForStaticID) { lazy val msg: String = em"${member.owner} does not have a companion class" lazy val explanation: String = em"An object that contains ${hl("@static")} members must have a companion class." } class PolymorphicMethodMissingTypeInParent(rsym: Symbol, parentSym: Symbol)(implicit ctx: Context) - extends Message(PolymorphicMethodMissingTypeInParentID) { - val kind: String = "Syntax" + extends SyntaxMsg(PolymorphicMethodMissingTypeInParentID) { lazy val msg: String = em"Polymorphic refinement $rsym without matching type in parent $parentSym is no longer allowed" lazy val explanation: String = em"""Polymorphic $rsym is not allowed in the structural refinement of $parentSym because @@ -2073,14 +1989,12 @@ object messages { } class ParamsNoInline(owner: Symbol)(implicit ctx: Context) - extends Message(ParamsNoInlineID) { - val kind: String = "Syntax" + extends SyntaxMsg(ParamsNoInlineID) { lazy val msg: String = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" lazy val explanation: String = "" } - class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends Message(JavaSymbolIsNotAValueID) { - val kind: String = "Type Mismatch" + class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends TypeMsg(JavaSymbolIsNotAValueID) { lazy val msg: String = { val kind = if (symbol is Package) em"$symbol" @@ -2091,8 +2005,7 @@ object messages { lazy val explanation: String = "" } - class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends Message(DoubleDefinitionID) { - val kind: String = "Duplicate Symbol" + class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends NamingMsg(DoubleDefinitionID) { lazy val msg: String = { def nameAnd = if (decl.name != previousDecl.name) " name and" else "" def details(implicit ctx: Context): String = @@ -2137,14 +2050,12 @@ object messages { lazy val explanation: String = "" } - class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends Message(ImportRenamedTwiceID) { - val kind: String = "Syntax" + class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends SyntaxMsg(ImportRenamedTwiceID) { lazy val msg: String = s"${ident.show} is renamed twice on the same import line." lazy val explanation: String = "" } - class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends Message(TypeTestAlwaysSucceedsID) { - val kind: String = "Syntax" + class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends SyntaxMsg(TypeTestAlwaysSucceedsID) { lazy val msg: String = { val addendum = if (foundCls != testCls) s" is a subtype of $testCls" @@ -2156,8 +2067,7 @@ object messages { // Relative of CyclicReferenceInvolvingImplicit and RecursiveValueNeedsResultType class TermMemberNeedsResultTypeForImplicitSearch(cycleSym: Symbol)(implicit ctx: Context) - extends Message(TermMemberNeedsNeedsResultTypeForImplicitSearchID) { - val kind: String = "Cyclic" + extends CyclicMsg(TermMemberNeedsNeedsResultTypeForImplicitSearchID) { lazy val msg: String = em"""$cycleSym needs result type because its right-hand side attempts implicit search""" lazy val explanation: String = em"""|The right hand-side of $cycleSym's definition requires an implicit search at the highlighted position. @@ -2165,14 +2075,12 @@ object messages { |""".stripMargin } - class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends Message(ClassCannotExtendEnumID) { - val kind: String = "Syntax" + class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends SyntaxMsg(ClassCannotExtendEnumID) { lazy val msg: String = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" lazy val explanation: String = "" } - class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends Message(NotAnExtractorID) { - val kind: String = "Syntax" + class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends SyntaxMsg(NotAnExtractorID) { lazy val msg: String = em"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method" lazy val explanation: String = em"""|An ${hl("unapply")} method should be defined in an ${hl("object")} as follow: @@ -2186,8 +2094,7 @@ object messages { } class MemberWithSameNameAsStatic()(implicit val ctx: Context) - extends Message(MemberWithSameNameAsStaticID) { - val kind: String = "Syntax" + extends SyntaxMsg(MemberWithSameNameAsStaticID) { lazy val msg: String = em"Companion classes cannot define members with same name as a ${hl("@static")} member" lazy val explanation: String = "" } @@ -2202,29 +2109,25 @@ object messages { } class TraitCompanionWithMutableStatic()(implicit val ctx: Context) - extends Message(TraitCompanionWithMutableStaticID) { - val kind: String = "Syntax" + extends SyntaxMsg(TraitCompanionWithMutableStaticID) { lazy val msg: String = em"Companion of traits cannot define mutable @static fields" lazy val explanation: String = "" } class LazyStaticField()(implicit val ctx: Context) - extends Message(LazyStaticFieldID) { - val kind: String = "Syntax" + extends SyntaxMsg(LazyStaticFieldID) { lazy val msg: String = em"Lazy @static fields are not supported" lazy val explanation: String = "" } class StaticOverridingNonStaticMembers()(implicit val ctx: Context) - extends Message(StaticOverridingNonStaticMembersID) { - val kind: String = "Syntax" + extends SyntaxMsg(StaticOverridingNonStaticMembersID) { lazy val msg: String = em"${hl("@static")} members cannot override or implement non-static ones" lazy val explanation: String = "" } class OverloadInRefinement(rsym: Symbol)(implicit val ctx: Context) - extends Message(OverloadInRefinementID) { - val kind: String = "Overload" + extends DeclarationMsg(OverloadInRefinementID) { lazy val msg: String = "Refinements cannot introduce overloaded definitions" lazy val explanation: String = em"""The refinement `$rsym` introduces an overloaded definition. @@ -2233,16 +2136,14 @@ object messages { class NoMatchingOverload(val alternatives: List[SingleDenotation], pt: Type)( err: Errors)(implicit val ctx: Context) - extends Message(NoMatchingOverloadID) { - val kind: String = "Type Mismatch" + extends TypeMismatchMsg(NoMatchingOverloadID) { lazy val msg: String = em"""None of the ${err.overloadedAltsStr(alternatives)} |match ${err.expectedTypeStr(pt)}""" lazy val explanation: String = "" } class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) - extends Message(StableIdentPatternID) { - val kind: String = "Type" + extends TypeMsg(StableIdentPatternID) { lazy val msg: String = em"""Stable identifier required, but $tree found""" lazy val explanation: String = "" @@ -2250,8 +2151,7 @@ object messages { class IllegalSuperAccessor(base: Symbol, memberName: Name, acc: Symbol, accTp: Type, - other: Symbol, otherTp: Type)(implicit val ctx: Context) extends Message(IllegalSuperAccessorID) { - val kind: String = "Reference" + other: Symbol, otherTp: Type)(implicit val ctx: Context) extends DeclarationMsg(IllegalSuperAccessorID) { lazy val msg: String = { // The mixin containing a super-call that requires a super-accessor val accMixin = acc.owner @@ -2305,8 +2205,7 @@ object messages { } class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) - extends Message(TraitParameterUsedAsParentPrefixID) { - val kind: String = "Reference" + extends DeclarationMsg(TraitParameterUsedAsParentPrefixID) { lazy val msg: String = s"${cls.show} cannot extend from a parent that is derived via its own parameters" lazy val explanation: String = @@ -2321,8 +2220,7 @@ object messages { } class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) - extends Message(UnknownNamedEnclosingClassOrObjectID) { - val kind: String = "Reference" + extends ReferenceMsg(UnknownNamedEnclosingClassOrObjectID) { lazy val msg: String = em"""no enclosing class or object is named '${hl(name.show)}'""" lazy val explanation: String = @@ -2335,22 +2233,19 @@ object messages { } class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context) - extends Message(IllegalCyclicTypeReferenceID) { - val kind: String = "Cyclic" + extends CyclicMsg(IllegalCyclicTypeReferenceID) { lazy val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" lazy val explanation: String = "" } class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) - extends Message(ErasedTypesCanOnlyBeFunctionTypesID) { - val kind: String = "Syntax" + extends SyntaxMsg(ErasedTypesCanOnlyBeFunctionTypesID) { lazy val msg: String = "Types with erased keyword can only be function types `(erased ...) => ...`" lazy val explanation: String = "" } class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(CaseClassMissingNonImplicitParamListID) { - val kind: String = "Syntax" + extends SyntaxMsg(CaseClassMissingNonImplicitParamListID) { lazy val msg: String = em"""|A ${hl("case class")} must have at least one non-implicit parameter list""" @@ -2361,8 +2256,7 @@ object messages { } class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(EnumerationsShouldNotBeEmptyID) { - val kind: String = "Syntax" + extends SyntaxMsg(EnumerationsShouldNotBeEmptyID) { lazy val msg: String = "Enumerations must contain at least one case" lazy val explanation: String = @@ -2375,8 +2269,7 @@ object messages { } class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context) - extends Message(AbstractCannotBeUsedForObjectsID) { - val kind: String = "Syntax" + extends SyntaxMsg(AbstractCannotBeUsedForObjectsID) { lazy val msg: String = em"${hl("abstract")} modifier cannot be used for objects" lazy val explanation: String = @@ -2391,8 +2284,7 @@ object messages { } class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context) - extends Message(ModifierRedundantForObjectsID) { - val kind: String = "Syntax" + extends SyntaxMsg(ModifierRedundantForObjectsID) { lazy val msg: String = em"${hl(modifier)} modifier is redundant for objects" lazy val explanation: String = @@ -2403,8 +2295,7 @@ object messages { } class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) - extends Message(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { - val kind: String = "Syntax" + extends SyntaxMsg(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { lazy val msg: String = i"explicit extends clause needed because both enum case and enum class have type parameters" lazy val explanation: String = @@ -2418,8 +2309,7 @@ object messages { } class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) - extends Message(IllegalRedefinitionOfStandardKindID) { - val kind: String = "Syntax" + extends SyntaxMsg(IllegalRedefinitionOfStandardKindID) { lazy val msg: String = em"illegal redefinition of standard $kindType $name" lazy val explanation: String = @@ -2429,8 +2319,7 @@ object messages { } class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) - extends Message(NoExtensionMethodAllowedID) { - val kind: String = "Syntax" + extends SyntaxMsg(NoExtensionMethodAllowedID) { lazy val msg: String = em"No extension method allowed here, since collective parameters are given" lazy val explanation: String = @@ -2441,8 +2330,7 @@ object messages { } class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) - extends Message(ExtensionMethodCannotHaveTypeParamsID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExtensionMethodCannotHaveTypeParamsID) { lazy val msg: String = i"Extension method cannot have type parameters since some were already given previously" lazy val explanation: String = @@ -2454,8 +2342,7 @@ object messages { } class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) - extends Message(ExtensionCanOnlyHaveDefsID) { - val kind: String = "Syntax" + extends SyntaxMsg(ExtensionCanOnlyHaveDefsID) { lazy val msg: String = em"Only methods allowed here, since collective parameters are given" lazy val explanation: String = @@ -2465,8 +2352,7 @@ object messages { } class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) - extends Message(UnexpectedPatternForSummonFromID) { - val kind: String = "Syntax" + extends SyntaxMsg(UnexpectedPatternForSummonFromID) { lazy val msg: String = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" lazy val explanation: String = @@ -2486,8 +2372,7 @@ object messages { } class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) - extends Message(AnonymousInstanceCannotBeEmptyID) { - val kind: String = "Syntax" + extends SyntaxMsg(AnonymousInstanceCannotBeEmptyID) { lazy val msg: String = i"anonymous instance must implement a type or have at least one extension method" lazy val explanation: String = @@ -2497,8 +2382,7 @@ object messages { } class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) - extends Message(TypeSpliceInValPatternID) { - val kind: String = "Syntax" + extends SyntaxMsg(TypeSpliceInValPatternID) { lazy val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead." lazy val explanation: String = @@ -2508,8 +2392,7 @@ object messages { } class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) - extends Message(ModifierNotAllowedForDefinitionID) { - val kind: String = "Syntax" + extends SyntaxMsg(ModifierNotAllowedForDefinitionID) { lazy val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition" lazy val explanation: String = "" diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index ee7b69153353..9fd0709c8048 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -28,7 +28,7 @@ import collection.mutable import config.Printers.{overload, typr, unapp} import TypeApplications._ -import reporting.messages.{UnexpectedPatternForSummonFrom, NotAMember, MissingIdent, TypeMismatch} +import reporting.messages.{UnexpectedPatternForSummonFrom, NotFoundMsg, TypeMismatch} import reporting.{trace, Message} import Constants.{Constant, IntTag, LongTag} import dotty.tools.dotc.reporting.messages.{UnapplyInvalidReturnType, NotAnExtractor, UnapplyInvalidNumberOfArguments} @@ -1068,10 +1068,7 @@ trait Applications extends Compatibility { state.reporter.pendingMessages match case msg :: Nil => msg.contained match - case msg: NotAMember => - memberName.isEmpty || msg.name == memberName - case msg: MissingIdent => - memberName.isEmpty || msg.name == memberName + case msg: NotFoundMsg => memberName.isEmpty || msg.name == memberName case _ => false case _ => false diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 13e0cab8b6ce..426f1487dcf8 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -450,7 +450,7 @@ class Typer extends Namer // we are in the arguments of a this(...) constructor call errorType(ex"$tree is not accessible from constructor arguments", tree.sourcePos) else - errorType(new MissingIdent(tree, kind, name), tree.sourcePos) + errorType(MissingIdent(tree, kind, name), tree.sourcePos) val tree1 = ownType match { case ownType: NamedType => diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala deleted file mode 100644 index f7bbfeccbb86..000000000000 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ /dev/null @@ -1,1862 +0,0 @@ -package dotty.tools -package dotc -package reporting - -import dotty.tools.backend.jvm.GenBCode -import dotty.tools.dotc.core.Contexts.Context -import dotty.tools.dotc.core.Types.WildcardType -import dotty.tools.dotc.parsing.Tokens -import dotty.tools.dotc.reporting.messages._ -import dotty.tools.dotc.transform.{CheckStatic, Erasure, PostTyper, TailRec} -import dotty.tools.dotc.typer.{FrontEnd, RefChecks} -import org.junit.Assert._ -import org.junit.Test - -class ErrorMessagesT ests extends ErrorMessagesTest { - // In the case where there are no errors, we can do "expectNoErrors" in the - // `Report` - @Test def noErrors = - checkMessagesAfter(FrontEnd.name)("""class Foo""") - .expectNoErrors - - @Test def caseClassExtendsEnum = - checkMessagesAfter(RefChecks.name) { - """ - |enum Foo { case A, B } - |case class Bar() extends Foo - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head - val ClassCannotExtendEnum(cls, parent) :: Nil = messages - assertEquals("Bar", cls.name.show) - assertEquals("Foo", parent.name.show) - assertEquals("", cls.owner.name.show) - } - - @Test def typeMismatch = - checkMessagesAfter(FrontEnd.name) { - """ - |object Foo { - | def bar: String = 1 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - val defn = ictx.definitions - - // Assert that we only got one error message - assertMessageCount(1, messages) - - // Pattern match out the expected error - val TypeMismatch(found, expected, _, _) :: Nil = messages - - // The type of the right hand side will actually be the constant 1, - // therefore we check if it "derivesFrom" `IntClass` - assert(found.derivesFrom(defn.IntClass), s"found was: $found") - - // The expected type is `scala.String` which we dealias to - // `java.lang.String` and compare with `=:=` to `defn.StringType` which - // is a type reference to `java.lang.String` - assert(expected.dealias =:= defn.StringType, s"expected was: $expected") - } - - @Test def overridesNothing = - checkMessagesAfter(RefChecks.name) { - """ - |object Foo { - | override def bar: Unit = {} - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverridesNothing(member) :: Nil = messages - assertEquals("bar", member.name.show) - } - - @Test def overridesNothingDifferentSignature = - checkMessagesAfter(RefChecks.name) { - """ - |class Bar { - | def bar(s: String): Unit = {} - | def bar(s: Int): Unit = {} - | final def bar(s: Long): Unit = {} - |} - |object Foo extends Bar { - | override def bar: Unit = {} - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverridesNothingButNameExists(member, sameName) :: Nil = messages - // check expected context data - assertEquals("bar", member.name.show) - assertEquals(3, sameName.size) - assert(sameName.forall(_.symbol.name.show == "bar"), - "at least one method had an unexpected name") - } - - @Test def forwardReference = - checkMessagesAfter(RefChecks.name) { - """ - |object Forward { - | def block = { - | a.toInt - | val b = 2 - | val a = BigDecimal("4") - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ForwardReferenceExtendsOverDefinition(value, definition) :: Nil = messages - assertEquals("value b", value.show) - assertEquals("value a", definition.show) - } - - @Test def unexpectedToken = - checkMessagesAfter(FrontEnd.name) { - """ - |object Forward { - | def val = "ds" - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ExpectedTokenButFound(expected, found) :: Nil = messages - assertEquals(Tokens.IDENTIFIER, expected) - assertEquals(Tokens.VAL, found) - } - - @Test def expectedToken = - checkMessagesAfter(FrontEnd.name) { - """ - |object Forward { - | def `val` = "ds" - |} - """.stripMargin - } - .expectNoErrors - - @Test def leftAndRightAssociative = - checkMessagesAfter(FrontEnd.name) { - """ - |object Ops { - | case class I(j: Int) { - | def +-(i: Int) = i - | def +:(i: Int) = i - | } - | val v = I(1) +- I(4) +: I(4) - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val MixedLeftAndRightAssociativeOps(op1, op2, op2LeftAssoc) :: Nil = messages - assertEquals("+-", op1.show) - assertEquals("+:", op2.show) - assertFalse(op2LeftAssoc) - } - - @Test def cantInstantiateAbstract = - checkMessagesAfter(RefChecks.name) { - """ - |object Scope { - | abstract class Concept - | val x = new Concept() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages - assertEquals("Concept", cls.name.show) - assertFalse("expected class", isTrait) - } - - @Test def cantInstantiateTrait = - checkMessagesAfter(RefChecks.name) { - """ - |object Scope { - | trait Concept - | val x = new Concept() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CantInstantiateAbstractClassOrTrait(cls, isTrait) :: Nil = messages - assertEquals("Concept", cls.name.show) - assertTrue("expected trait", isTrait) - } - - @Test def overloadedMethodNeedsReturnType = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | def foo(i: Int) = foo(i.toString) - | def foo(s: String) = s - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("foo", cycleSym.name.show) - } - - @Test def i1731 = - checkMessagesAfter(FrontEnd.name) { - """ - |case class Foo[T](x: T) - |object Foo { def apply[T]() = Foo(null.asInstanceOf[T]) } - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("apply", cycleSym.name.show) - } - - @Test def recursiveMethodNeedsReturnType = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | def i = i + 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("i", cycleSym.name.show) - } - - @Test def recursiveValueNeedsReturnType = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | lazy val i = i + 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val RecursiveValueNeedsResultType(cycleSym) :: Nil = messages - assertEquals("i", cycleSym.name.show) - } - - @Test def recursiveValueNeedsReturnType2 = - checkMessagesAfter(FrontEnd.name) { - """ - |class Scope() { - | lazy val i = j + 5 - | lazy val j = i - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val RecursiveValueNeedsResultType(cycleSym) :: Nil = messages - assertEquals("i", cycleSym.name.show) - } - - @Test def cyclicReferenceInvolving = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | val x: T = ??? - | type T <: x.type // error: cyclic reference involving value x - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CyclicReferenceInvolving(denot) :: Nil = messages - assertEquals("value x", denot.show) - } - - @Test def cyclicReferenceInvolving2 = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | implicit val x: T = ??? - | type T <: x.type // error: cyclic reference involving value x - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CyclicReferenceInvolving(denot) :: Nil = messages - assertEquals("value x", denot.show) - } - - @Test def mutualRecursionre_i2001 = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def odd(x: Int) = if (x == 0) false else !even(x-1) - | def even(x: Int) = if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("odd", cycleSym.name.show) - } - - @Test def mutualRecursion_i2001a = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def odd(x: Int) = if (x == 0) false else !even(x-1) - | def even(x: Int) = { - | def foo = { - | if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type - | } - | false - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("odd", cycleSym.name.show) - } - - @Test def mutualRecursion_i2001b = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def odd(x: Int) = if (x == 0) false else !even(x-1) - | def even(x: Int) = { - | val foo = { - | if (x == 0) true else !odd(x-1) // error: overloaded or recursive method needs result type - | } - | false - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OverloadedOrRecursiveMethodNeedsResultType(cycleSym) :: Nil = messages - assertEquals("odd", cycleSym.name.show) - } - - @Test def termMemberNeedsResultTypeForImplicitSearch = - checkMessagesAfter(FrontEnd.name) { - """ - |object implicitDefs { - | def foo(implicit x: String) = 1 - | def bar() = { - | implicit val x = foo - | x - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages - assertEquals("x", cycleSym.name.show) - } - - @Test def implicitSearchForcesImplicitRetType_i4709 = - checkMessagesAfter(FrontEnd.name) { - """ - |import scala.language.implicitConversions - | - |class Context - |class ContextBase { def settings = 1 } - | - |class Test { - | implicit def toBase(ctx: Context): ContextBase = ??? - | - | def test(ctx0: Context) = { - | implicit val ctx = { ctx0.settings; ??? } - | } - |} - """.stripMargin - } - .expect{ (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages - assertEquals("ctx", cycleSym.name.show) - } - - @Test def implicitSearchForcesNonImplicitRetTypeOnExplicitImport_i3253 = - checkMessagesAfter(FrontEnd.name) { - """ - |import Test.test - | - |object Test { - | def test = " " * 10 - |} - """.stripMargin - } - .expect{ (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TermMemberNeedsResultTypeForImplicitSearch(cycleSym) :: Nil = messages - assertEquals("test", cycleSym.name.show) - } - - @Test def superQualMustBeParent = - checkMessagesAfter(FrontEnd.name) { - """ - |class A { - | def foo(): Unit = () - |} - | - |class B { - |} - | - |class C extends A { - | super[B].foo - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val SuperQualMustBeParent(qual, cls) :: Nil = messages - - assertEquals("B", qual.show) - assertEquals("class C", cls.show) - } - - @Test def ambiguousImport = - checkMessagesAfter(FrontEnd.name) { - """ - |object A { - | class ToBeImported - |} - |object B { - | class ToBeImported - |} - |class C { - | import A.ToBeImported - | import B.ToBeImported - | - | val value: ToBeImported = ??? - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - import typer.Typer.BindingPrec._ - - assertMessageCount(1, messages) - val AmbiguousImport(name, newPrec, prevPrec, prevCtx) :: Nil = messages - assertEquals("ToBeImported", name.show) - assertEquals(NamedImport, newPrec) - assertEquals(NamedImport, prevPrec) - } - - @Test def methodDoesNotTakeParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |object Scope { - | def foo = () - | foo() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val msg @ MethodDoesNotTakeParameters(tree) = messages.head - - assertEquals("Scope.foo", tree.show) - assertEquals("method foo", msg.methodSymbol.show) - } - - @Test def methodDoesNotTakeMoreParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |object Scope{ - | def foo(a: Int) = () - | foo(1)("2") - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val msg @ MethodDoesNotTakeParameters(tree) = messages.head - - assertEquals("Scope.foo(1)", tree.show) - assertEquals("method foo", msg.methodSymbol.show) - } - - @Test def ambiugousOverloadWithWildcard = - checkMessagesAfter(FrontEnd.name) { - """object Context { - | trait A { - | def foo(s: String): String - | def foo: String = foo("foo") - | } - | object B extends A { - | def foo(s: String): String = s - | } - | B.foo - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val AmbiguousOverload(tree, List(alt1, alt2), pt: WildcardType) :: Nil = messages - assertEquals("method foo", alt1.show) - assertEquals("(s: String): String", alt1.info.show) - assertEquals("method foo", alt2.show) - } - - @Test def reassignmentToVal = - checkMessagesAfter(FrontEnd.name) { - """ - |class Context { - | val value = 3 - | value = 4 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ReassignmentToVal(name) :: Nil = messages - assertEquals("value", name.show) - } - - @Test def typeDoesNotTakeParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |trait WithOutParams - |class Extending extends WithOutParams[String] - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TypeDoesNotTakeParameters(tpe, params) :: Nil = messages - assertEquals("WithOutParams", tpe.show) - } - - @Test def parameterizedTypeLacksParameters = - checkMessagesAfter(FrontEnd.name) { - """ - |trait WithParams(s: String) - |class Extending extends WithParams - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ParameterizedTypeLacksArguments(symbol) :: Nil = messages - assertEquals("trait WithParams", symbol.show) - } - - @Test def varValParametersMayNotBeCallByName = - checkMessagesAfter(FrontEnd.name) { - "trait Trait(val noNoNo: => String)" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val VarValParametersMayNotBeCallByName(name, false) :: Nil = messages - assertEquals("noNoNo", name.show) - } - - @Test def missingTypeParameter = - checkMessagesAfter(FrontEnd.name) { - """object Scope { - | val value: List = null - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val MissingTypeParameterFor(tpe) :: Nil = messages - assertEquals("List", tpe.show) - } - - @Test def missingTypeParameterInTypeApp = - checkMessagesAfter(RefChecks.name) { - """object Scope { - | def f[T] = ??? - | val x = f[List] - | val y = f[Either] - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(2, messages) - assertEquals("Missing type parameter for List", messages(1).msg) - assertEquals("Missing type parameters for Either", messages(0).msg) - } - - @Test def doesNotConformToBound = - checkMessagesAfter(RefChecks.name) { - """class WithParam[A <: List[Int]] - |object Scope { - | val value: WithParam[Int] = null - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoesNotConformToBound(tpe, which, bound) :: Nil = messages - assertEquals("Int", tpe.show) - assertEquals("upper", which) - assertEquals("List[Int]", bound.show) - } - - @Test def doesNotConformToSelfType = - checkMessagesAfter(RefChecks.name) { - """class Base - |trait BlendItIn { - | this: Base => - |} - |class Blended extends BlendItIn - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoesNotConformToSelfType(category, selfType, cls, otherSelf, relation, other) :: Nil = messages - assertEquals("illegal inheritance", category) - assertEquals("Blended", selfType.show) - assertEquals("class Blended", cls.show) - assertEquals("Base", otherSelf.show) - assertEquals("parent", relation) - assertEquals("trait BlendItIn", other.show) - } - - @Test def doesNotConformToSelfTypeCantBeInstantiated = - checkMessagesAfter(RefChecks.name) { - """class Base - |class RequiresBase { self: Base => } - |object Scope { - | val x = new RequiresBase - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoesNotConformToSelfTypeCantBeInstantiated(tpe, selfType) :: Nil = messages - assertEquals("RequiresBase", tpe.show) - assertEquals("Base", selfType.show) - } - - @Test def abstractValueMayNotHaveFinalModifier = - checkMessagesAfter(FrontEnd.name) { - """abstract class Foo { - | final val s: String - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val AbstractMemberMayNotHaveModifier(symbol, flags) :: Nil = messages - assertEquals("value s", symbol.show) - assertEquals("final", flags.flagsString) - } - - @Test def typesAndTraitsCantBeImplicit = - checkMessagesAfter(FrontEnd.name) { - """class Foo { - | implicit trait S - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val TypesAndTraitsCantBeImplicit() :: Nil = messages - } - - @Test def onlyClassesCanBeAbstract = - checkMessagesAfter(FrontEnd.name) { - """class Foo { - | abstract val s: String - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val OnlyClassesCanBeAbstract(symbol) :: Nil = messages - assertEquals("value s", symbol.show) - } - - @Test def abstractOverrideOnlyInTraits = - checkMessagesAfter(FrontEnd.name) { - """class Foo { - | abstract override val s: String = "" - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val AbstractOverrideOnlyInTraits(symbol) :: Nil = messages - assertEquals("value s", symbol.show) - } - - @Test def traitMayNotBeFinal = - checkMessagesAfter(FrontEnd.name) { - """final trait Foo""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val TraitsMayNotBeFinal(symbol) :: Nil = messages - assertEquals("trait Foo", symbol.show) - } - - @Test def nativeMemberMayNotHaveImplementation = - checkMessagesAfter(FrontEnd.name) { - """trait Foo { - | @native def foo() = 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val NativeMembersMayNotHaveImplementation(symbol) :: Nil = messages - assertEquals("method foo", symbol.show) - } - - @Test def onlyClassesCanHaveDeclaredButUndefinedMembers = - checkMessagesAfter(FrontEnd.name) { - """object Foo { - | def foo(): Int - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val OnlyClassesCanHaveDeclaredButUndefinedMembers(symbol) :: Nil = messages - assertEquals("method foo", symbol.show) - } - - @Test def cannotExtendAnyval = - checkMessagesAfter(FrontEnd.name) { - """trait Foo extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CannotExtendAnyVal(symbol) :: Nil = messages - assertEquals("trait Foo", symbol.show) - } - - @Test def cannotHaveSameNameAs = - checkMessagesAfter(RefChecks.name) { - """trait Foo { - | class A - |} - |class B extends Foo { - | class A - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CannotHaveSameNameAs(symbol, cls, _) :: Nil = messages - assertEquals("class A", symbol.show) - assertEquals("class A", cls.show) - } - - @Test def valueClassesMayNotDefineInner = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | class Inner - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotDefineInner(valueClass, inner) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("class Inner", inner.show) - } - - @Test def valueClassesMayNotDefineNonParameterField = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | val illegal: Int - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotDefineNonParameterField(valueClass, field) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("value illegal", field.show) - } - - @Test def valueClassesMayNotDefineASecondaryConstructor = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | def this() = this(2) - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotDefineASecondaryConstructor(valueClass, constuctor) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("constructor MyValue", constuctor.show) - } - - @Test def valueClassesMayNotContainInitalization = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: Int) extends AnyVal { - | println("Hallo?") - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotContainInitalization(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassesMayNotBeContained = - checkMessagesAfter(RefChecks.name) { - """class Outer { - | class MyValue(i: Int) extends AnyVal - |} - |""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotBeContainted(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassesMayNotWrapItself = - checkMessagesAfter(RefChecks.name) { - """class MyValue(i: MyValue) extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassesMayNotWrapItself(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassParameterMayNotBeVar = - checkMessagesAfter(RefChecks.name) { - """class MyValue(var i: Int) extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassParameterMayNotBeAVar(valueClass, param) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("variable i", param.show) - } - - @Test def valueClassNeedsOneVal = - checkMessagesAfter(RefChecks.name) { - """class MyValue() extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassNeedsOneValParam(valueClass) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - } - - @Test def valueClassParameterMayNotBeCallByName = - checkMessagesAfter(RefChecks.name) { - """class MyValue(a: => Int) extends AnyVal""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ValueClassParameterMayNotBeCallByName(valueClass, param) :: Nil = messages - assertEquals("class MyValue", valueClass.show) - assertEquals("value a", param.show) - } - - @Test def onlyCaseClassOrCaseObjectAllowed = - checkMessagesAfter(FrontEnd.name) { - """case Foobar""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val err :: Nil = messages - assertEquals(err, OnlyCaseClassOrCaseObjectAllowed()) - } - - @Test def expectedClassOrObjectDef = - checkMessagesAfter(FrontEnd.name) { - """Foo""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val err :: Nil = messages - assertEquals(err, ExpectedToplevelDef()) - } - - @Test def implicitClassPrimaryConstructorArity = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | implicit class Foo(i: Int, s: String) - |} - """.stripMargin - } - .expect { (itcx, messages) => - implicit val ctx: Context = itcx - assertMessageCount(1, messages) - val err :: Nil = messages - assertEquals(err, ImplicitClassPrimaryConstructorArity()) - } - - @Test def superCallsNotAllowedInline = - checkMessagesAfter(RefChecks.name) { - """ - |class A { - | def foo(): Unit = () - |} - | - |class B extends A { - | inline def bar(): Unit = super.foo() - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val err :: Nil = messages - val SuperCallsNotAllowedInlineable(symbol) = err - assertEquals("method bar", symbol.show) - } - - @Test def wildcardOnTypeArgumentNotAllowedOnNew = - checkMessagesAfter(RefChecks.name) { - """ - |object TyperDemo { - | class Team[A] - | val team = new Team[?] - |}""".stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(err, WildcardOnTypeArgumentNotAllowedOnNew()) - } - - @Test def wrongNumberOfParameters = - checkMessagesAfter(RefChecks.name) { - """object NumberOfParams { - | def unary[T](x: T => Unit) = () - | unary((x, y) => ()) - |} """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(err, WrongNumberOfParameters(1)) - } - - @Test def duplicatePrivateProtectedQualifier = - checkMessagesAfter(FrontEnd.name) { - """class Test { - | private[Test] protected[this] def foo(): Unit = () - |} """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(DuplicatePrivateProtectedQualifier(), err) - } - - @Test def expectedStartOfTopLevelDefinition = - checkMessagesAfter(FrontEnd.name) { - """private Test {}""" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val err :: Nil = messages - - assertEquals(ExpectedStartOfTopLevelDefinition(), err) - } - - @Test def missingReturnTypeWithReturnStatement = - checkMessagesAfter(FrontEnd.name) { - """class BadFunction { - | def bad() = { return "fail" } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - - val MissingReturnTypeWithReturnStatement(method) :: Nil = messages - assertEquals(method.name.show, "bad") - } - - @Test def noReturnInInline = - checkMessagesAfter(FrontEnd.name) { - """class BadFunction { - | inline def usesReturn: Int = { return 42 } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - - val NoReturnFromInlineable(method) :: Nil = messages - assertEquals("method usesReturn", method.show) - } - - @Test def returnOutsideMethodDefinition = - checkMessagesAfter(FrontEnd.name) { - """object A { - | return 5 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ReturnOutsideMethodDefinition(owner) :: Nil = messages - assertEquals("object A", owner.show) - } - - @Test def extendFinalClass = checkMessagesAfter(RefChecks.name) { - """final class A - | - |class B extends A - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ExtendFinalClass(extender, parent) :: Nil = messages - assertEquals(extender.show, "class B") - assertEquals(parent.show, "class A") - } - - @Test def tailrecNotApplicableNeitherPrivateNorFinal = - checkMessagesAfter(TailRec.name) { - """ - |class Foo { - | @scala.annotation.tailrec - | def foo: Unit = foo - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val TailrecNotApplicable(method) :: Nil = messages - assertEquals(method.show, "method foo") - } - - @Test def expectedTypeBoundOrEquals = - checkMessagesAfter(FrontEnd.name) { - """object typedef { - | type asd > Seq - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ExpectedTypeBoundOrEquals(found) :: Nil = messages - assertEquals(Tokens.IDENTIFIER, found) - } - - @Test def classAndCompanionNameClash = - checkMessagesAfter(RefChecks.name) { - """ - |class T { - | class G - |} - |object T { - | trait G - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val ClassAndCompanionNameClash(cls, other) :: Nil = messages - - assertEquals("class T", cls.owner.show) - assertEquals("class G", cls.show) - assertEquals("object T", other.owner.show) - assertEquals("trait G", other.show) - - } - - @Test def onlyFunctionsCanBeFollowedByUnderscore = - checkMessagesAfter(FrontEnd.name) { - """ - |class T { - | def main(args: Array[String]): Unit = { - | val n = "T" - | val func = n _ - | } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val OnlyFunctionsCanBeFollowedByUnderscore(tp) :: Nil = messages - assertEquals("String", tp.show) - } - - @Test def missingEmptyArgumentList = - checkMessagesAfter(FrontEnd.name) { - """ - |class Test { - | def greet(): String = "Hello" - | def main(args: Array[String]): Unit = { - | greet - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val MissingEmptyArgumentList(method) :: Nil = messages - assertEquals("method greet", method.show) - } - - @Test def duplicateNamedTypeParameter = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | def f[A, B]() = ??? - | f[A=Any, A=Any]() - | f[B=Any, B=Any]() - |} - | - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(2, messages) - val DuplicateNamedTypeParameter(n2) :: DuplicateNamedTypeParameter(n1) :: Nil = messages - assertEquals("A", n1.show) - assertEquals("B", n2.show) - } - - @Test def undefinedNamedTypeParameter = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | def f[A, B]() = ??? - | f[A=Any, C=Any]() - | f[C=Any, B=Any]() - |} - | - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(2, messages) - val UndefinedNamedTypeParameter(n2, l2) :: UndefinedNamedTypeParameter(n1, l1) :: Nil = messages - val tpParams = List("A", "B") - assertEquals("C", n1.show) - assertEquals(tpParams, l1.map(_.show)) - assertEquals("C", n2.show) - assertEquals(tpParams, l2.map(_.show)) - - } - - @Test def illegalStartOfStatement = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | { with } - | { private ) } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(2, messages) - val errWithModifier :: err :: Nil = messages - - assertEquals(IllegalStartOfStatement(isModifier = false), err) - assertEquals(IllegalStartOfStatement(isModifier = true), errWithModifier) - } - - @Test def traitIsExpected = - checkMessagesAfter(FrontEnd.name) { - """ - |class A - |class B - | - |object Test { - | def main(args: Array[String]): Unit = { - | val a = new A with B - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TraitIsExpected(symbol) :: Nil = messages - assertEquals("class B", symbol.show) - } - - @Test def traitRedefinedFinalMethodFromAnyRef = - checkMessagesAfter(RefChecks.name) { - """ - |trait C { - | def wait (): Unit - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val TraitRedefinedFinalMethodFromAnyRef(method) = messages.head - assertEquals("method wait", method.show) - } - - @Test def packageNameAlreadyDefined = - checkMessagesAfter(FrontEnd.name) { - """ - |package bar { } - |object bar { } - | - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - val PackageNameAlreadyDefined(pkg) = messages.head - assertEquals(pkg.show, "object bar") - } - - @Test def unapplyInvalidNumberOfArguments = - checkMessagesAfter(FrontEnd.name) { - """ - |case class Boo(a: Int, b: String) - | - |object autoTuplingNeg2 { - | val z = Boo(1, "foo") - | - | z match { - | case Boo(a, b, c) => a - | } - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnapplyInvalidNumberOfArguments(qual, argTypes) :: Nil = messages - assertEquals("Boo", qual.show) - assertEquals("(class Int, type String)", argTypes.map(_.typeSymbol).mkString("(", ", ", ")")) - } - - @Test def unapplyInvalidReturnType = - checkMessagesAfter("typer") { - """ - |class A(val i: Int) - | - |object A { - | def unapply(a: A): Int = a.i - | def test(a: A) = a match { - | case A() => 1 - | } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnapplyInvalidReturnType(unapplyResult, unapplyName) :: Nil = messages - assertEquals("Int", unapplyResult.show) - assertEquals("unapply", unapplyName.show) - } - - @Test def unapplySeqInvalidReturnType = - checkMessagesAfter("typer") { - """ - |class A(val i: Int) - | - |object A { - | def unapplySeq(a: A): Int = a.i - | def test(a: A) = a match { - | case A() => 1 - | } - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnapplyInvalidReturnType(unapplyResult, unapplyName) :: Nil = messages - assertEquals("Int", unapplyResult.show) - assertEquals("unapplySeq", unapplyName.show) - } - - @Test def staticOnlyAllowedInsideObjects = - checkMessagesAfter(CheckStatic.name) { - """ - |class Foo { - | @annotation.static def bar(): Unit = bar() - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - val StaticFieldsOnlyAllowedInObjects(field) = messages.head - assertEquals(field.show, "method bar") - } - - @Test def staticShouldPrecedeNonStatic = - checkMessagesAfter(CheckStatic.name) { - """ - |class Foo - |object Foo { - | val foo = 1 - | @annotation.static val bar = 2 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - val StaticFieldsShouldPrecedeNonStatic(field, _) = messages.head - assertEquals(field.show, "value bar") - } - - @Test def cyclicInheritance = - checkMessagesAfter(FrontEnd.name) { - "class A extends A" - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val CyclicInheritance(symbol, _) :: Nil = messages - assertEquals("class A", symbol.show) - } - - @Test def missingCompanionForStatic = - checkMessagesAfter(CheckStatic.name) { - """ - |object Foo { - | @annotation.static def bar(): Unit = () - |} - """.stripMargin - }.expect { (itcx, messages) => - implicit val ctx: Context = itcx - val MissingCompanionForStatic(member) = messages.head - assertEquals(member.show, "method bar") - } - - @Test def polymorphicMethodMissingTypeInParent = - checkMessagesAfter(FrontEnd.name) { - """ - |object Test { - | import scala.reflect.Selectable.reflectiveSelectable - | def foo(x: { def get[T](a: T): Int }) = 5 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - - assertMessageCount(1, messages) - val PolymorphicMethodMissingTypeInParent(rsym, parentSym) = messages.head - assertEquals("method get", rsym.show) - assertEquals("class Object", parentSym.show) - } - - @Test def typeDoubleDeclaration = - checkMessagesAfter(FrontEnd.name) { - """ - |class Foo { - | val a = 1 - | val a = 2 - |} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val DoubleDefinition(symbol, previousSymbol, _) :: Nil = messages - assertEquals(symbol.name.mangledString, "a") - } - - @Test def renameImportTwice = - checkMessagesAfter(PostTyper.name) { - """ - |import java.lang.{Integer => Foo, Integer => Baz} - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val (msg @ ImportRenamedTwice(ident)) :: Nil = messages - assertEquals(ident.show, "Integer") - } - - @Test def tailRecOptimisation = - checkMessagesAfter(FrontEnd.name) { - """ - |import scala.annotation.tailrec - |@tailrec - |object Test { - | @tailrec val a = "" - | @tailrec var b = "" - |} - |@tailrec - |class Test {} - | - """.stripMargin - }.expect{ (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(4, messages) - - val tailRecMessages = messages.map({ case TailrecNotApplicable(sym) => sym.showKind }).toSet - assertEquals(tailRecMessages, Set("variable", "value", "object", "class")) - } - - @Test def notAnExtractor() = - checkMessagesAfter(FrontEnd.name) { - """ - | trait Foo - | object Foo - | object Test { - | def test(foo: Foo) = foo match { - | case Foo(name) => ??? - | } - | } - """.stripMargin - }.expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val NotAnExtractor(tree) = messages.head - assertEquals("Foo", tree.show) - } - - @Test def memberWithSameNameAsStatic() = - checkMessagesAfter(CheckStatic.name) { - """ - |import scala.annotation.static - |class Camp { - | val name = "" - |} - |object Camp { - | @static val name = "" - |} - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[MemberWithSameNameAsStatic]) - assertEquals(message.msg, "Companion classes cannot define members with same name as a @static member") - } - - @Test def companionOfTraitWithMutableStatic() = - checkMessagesAfter(CheckStatic.name) { - """ - | import scala.annotation.static - | trait Test - | object Test { - | @static var myStatic = "" - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[TraitCompanionWithMutableStatic]) - assertEquals( - "Companion of traits cannot define mutable @static fields", - message.msg - ) - } - - @Test def lazyStaticField() = - checkMessagesAfter(CheckStatic.name) { - """ - | import scala.annotation.static - | class Test - | object Test { - | @static lazy val myStatic = "" - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[LazyStaticField]) - assertEquals( - "Lazy @static fields are not supported", - message.msg - ) - } - - @Test def staticOverridingNonStatic() = - checkMessagesAfter(CheckStatic.name) { - """ - | import scala.annotation.static - | trait Foo { - | val foo = "" - | } - | class Test - | object Test extends Foo { - | @static val foo = "" - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[StaticOverridingNonStaticMembers]) - assertEquals( - "@static members cannot override or implement non-static ones", - message.msg - ) - } - - @Test def StableIdentifiers() = - checkMessagesAfter(FrontEnd.name) { - """ - | object Test { - | var x = 2 - | def test = 2 match { - | case `x` => x + 1 - | } - | } - """.stripMargin - }.expect { (_, messages) => - assertMessageCount(1, messages) - val message = messages.head - assertTrue(message.isInstanceOf[StableIdentPattern]) - assertEquals( - "Stable identifier required, but `x` found", - message.msg - ) - } - - @Test def traitParametersUsedAsParentPrefix() = - checkMessagesAfter(RefChecks.name) { - """ - |class Outer { - | trait Inner - | trait Test(val outer: Outer) extends outer.Inner - |} - |""".stripMargin - }.expect { - (ictx, messages) => - implicit val ctx: Context = ictx - val TraitParameterUsedAsParentPrefix(cls) :: Nil = messages - assertEquals("trait Test", cls.show) - assertEquals( - s"${cls.show} cannot extend from a parent that is derived via its own parameters", - messages.head.msg - ) - } - - @Test def unknownNamedEnclosingClassOrObject() = - checkMessagesAfter(RefChecks.name) { - """ - |class TestObject { - | private[doesNotExist] def test: Int = 5 - |} - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val UnknownNamedEnclosingClassOrObject(name) :: Nil = messages - assertEquals("doesNotExist", name.show) - } - - @Test def illegalCyclicTypeReference() = - checkMessagesAfter(RefChecks.name) { - """ - |type X = List[X] - """.stripMargin - } - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val IllegalCyclicTypeReference(sym, where, lastChecked) :: Nil = messages - assertEquals("type X", sym.show) - assertEquals("alias", where) - assertEquals("List[X]", lastChecked.show) - } - - @Test def erasedTypesCanOnlyBeFunctionTypesSuccess() = - checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int) => Int): Int = 1") - .expectNoErrors - - @Test def erasedTypesCanOnlyBeFunctionTypesFailed() = - checkMessagesAfter(FrontEnd.name) ("def foo(f: (erased Int)): Int = 1") - .expect { (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val ErasedTypesCanOnlyBeFunctionTypes() :: Nil = messages - assertEquals("Types with erased keyword can only be function types `(erased ...) => ...`", messages.head.msg) - } - - @Test def caseClassMissingParamListSuccessful = - checkMessagesAfter(FrontEnd.name) ("case class Test()") - .expectNoErrors - - @Test def caseClassMissingParamListFailed = - checkMessagesAfter(FrontEnd.name) ("case class Test") - .expect { - (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CaseClassMissingParamList(tpe) :: Nil = messages - assertEquals("A case class must have at least one parameter list", messages.head.msg) - } - - @Test def caseClassMissingNonImplicitParamListSuccessful = - checkMessagesAfter(FrontEnd.name) ("case class Test()(using foo: String)") - .expectNoErrors - - @Test def caseClassMissingNonImplicitParamListFailed = - checkMessagesAfter(FrontEnd.name) ("case class Test(using foo: String)") - .expect { - (ictx, messages) => - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val CaseClassMissingNonImplicitParamList(tpe) :: Nil = messages - assertEquals("A case class must have at least one non-implicit parameter list", messages.head.msg) - } - - @Test def enumMustContainOneCase = - checkMessagesAfter(RefChecks.name) { - """ - |enum Foo { } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val EnumerationsShouldNotBeEmpty(typeDef) :: Nil = messages - assertEquals("Enumerations must contain at least one case", errorMsg) - assertEquals("Foo", typeDef.name.toString) - } - - @Test def objectsCannotBeAbstract = - checkMessagesAfter(RefChecks.name) { - """ - |abstract object Foo { } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val AbstractCannotBeUsedForObjects(mdef) :: Nil = messages - assertEquals("abstract modifier cannot be used for objects", errorMsg) - assertEquals("Foo", mdef.name.toString) - } - - @Test def sealedOnObjectsIsRedundant = - checkMessagesAfter(RefChecks.name) { - """ - |sealed object Foo { } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val ModifierRedundantForObjects(mdef, "sealed") :: Nil = messages - assertEquals("sealed modifier is redundant for objects", errorMsg) - assertEquals("Foo", mdef.name.toString) - } - - @Test def enumAndCaseWithTypesNeedExplicitExtends = - checkMessagesAfter(RefChecks.name) { - """ - |enum E[T,U,V] { - | case C[X,Y,Z](x: X, y: Y, z: Z) - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef, caseDef) :: Nil = messages - assertEquals("explicit extends clause needed because both enum case and enum class have type parameters", errorMsg) - assertEquals("E", enumDef.name.toString) - assertEquals("C", caseDef.name.toString) - } - - @Test def illegalRedefinitionOfStandardKind = - checkMessagesAfter(RefChecks.name) { - """ package scala { - | class Any() - | } - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val IllegalRedefinitionOfStandardKind(kind, name) :: Nil = messages - assertEquals("illegal redefinition of standard class Any", errorMsg) - assertEquals("class", kind) - assertEquals("Any", name.toString) - } - - @Test def unexpectedPatternForSummonFrom = - checkMessagesAfter(RefChecks.name) { - """import compiletime.summonFrom - |inline def a = summonFrom { - | case x => ??? - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val UnexpectedPatternForSummonFrom(x) :: Nil = messages - assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) - assertEquals("x", x.show) - } - - @Test def unexpectedPatternForSummonWithPatternBinder = - checkMessagesAfter(RefChecks.name) { - """import compiletime.summonFrom - |inline def a = summonFrom { - | case x@String => ??? - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val UnexpectedPatternForSummonFrom(x) :: Nil = messages - assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) - assertEquals("given x @ String", x.show) - } - - @Test def typeSplicesInValPatterns = - checkMessagesAfter(RefChecks.name) { - s"""import scala.quoted._ - |object Foo { - | def f(using q: QuoteContext) = { - | val t: Type[Int] = ??? - | val '[ *:[$$t] ] = ??? - | } - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val TypeSpliceInValPattern(x) :: Nil = messages - assertEquals("Type splices cannot be used in val patterns. Consider using `match` instead.", errorMsg) - assertEquals("t", x.show) - } - - @Test def modifierNotAllowedForDefinition = - checkMessagesAfter(RefChecks.name) { - """object Test { - | opaque def o: Int = 3 - |} - """.stripMargin - } - .expect { (ictx, messages) ⇒ - implicit val ctx: Context = ictx - assertMessageCount(1, messages) - val errorMsg = messages.head.msg - val ModifierNotAllowedForDefinition(x) :: Nil = messages - assertEquals("Modifier `opaque` is not allowed for this definition", errorMsg) - assertEquals("opaque", x.flagsString) - } -} diff --git a/tests/neg-custom-args/explicit-nulls/i7883.check b/tests/neg-custom-args/explicit-nulls/i7883.check index dd2a9ce6ae02..57775b962f3f 100644 --- a/tests/neg-custom-args/explicit-nulls/i7883.check +++ b/tests/neg-custom-args/explicit-nulls/i7883.check @@ -6,13 +6,13 @@ | (c: Char): Option[List[Char]] | (s: CharSequence): Option[List[String]] | match arguments (String | UncheckedNull) --- [E006] Unbound Identifier Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:30 ------------------------------ +-- [E006] Not Found Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:30 --------------------------------------- 6 | case r(hd, tl) => Some((hd, tl)) // error // error // error | ^^ | Not found: hd longer explanation available when compiling with `-explain` --- [E006] Unbound Identifier Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:34 ------------------------------ +-- [E006] Not Found Error: tests/neg-custom-args/explicit-nulls/i7883.scala:6:34 --------------------------------------- 6 | case r(hd, tl) => Some((hd, tl)) // error // error // error | ^^ | Not found: tl diff --git a/tests/neg/3559d.check b/tests/neg/3559d.check index 213f4f165f68..128093d8579a 100644 --- a/tests/neg/3559d.check +++ b/tests/neg/3559d.check @@ -1,4 +1,4 @@ --- [E006] Unbound Identifier Error: tests/neg/3559d.scala:7:9 ---------------------------------------------------------- +-- [E006] Not Found Error: tests/neg/3559d.scala:7:9 ------------------------------------------------------------------- 7 | this(f) // error | ^ | Not found: f diff --git a/tests/neg/bad-unapplies.check b/tests/neg/bad-unapplies.check index 5eb12d7dffd4..a2ee445b7db5 100644 --- a/tests/neg/bad-unapplies.check +++ b/tests/neg/bad-unapplies.check @@ -19,7 +19,7 @@ longer explanation available when compiling with `-explain` | D cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method longer explanation available when compiling with `-explain` --- [E050] Reference Error: tests/neg/bad-unapplies.scala:25:9 ---------------------------------------------------------- +-- [E050] Type Error: tests/neg/bad-unapplies.scala:25:9 --------------------------------------------------------------- 25 | case E("2") => // error (value unapply in object E does not take parameters) | ^ | value unapply in object E does not take parameters @@ -31,7 +31,7 @@ longer explanation available when compiling with `-explain` | Wrong number of argument patterns for F; expected: () longer explanation available when compiling with `-explain` --- [E006] Unbound Identifier Error: tests/neg/bad-unapplies.scala:27:9 ------------------------------------------------- +-- [E006] Not Found Error: tests/neg/bad-unapplies.scala:27:9 ---------------------------------------------------------- 27 | case G("2") => // error (Not found: G) | ^ | Not found: G diff --git a/tests/neg/doubleDefinition.check b/tests/neg/doubleDefinition.check index e3df6788d3b0..7731951f123e 100644 --- a/tests/neg/doubleDefinition.check +++ b/tests/neg/doubleDefinition.check @@ -1,122 +1,122 @@ --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:14:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:14:4 ---------------------------------------------------------- 14 | def foo(x: List[B]): Function1[B, B] = ??? // error: same jvm signature | ^ | Double definition: | def foo(x: List[A]): A => A in class Test2 at line 13 and | def foo(x: List[B]): B => B in class Test2 at line 14 | have the same type after erasure. --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:21:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:21:4 ---------------------------------------------------------- 21 | def foo(x: List[A]): Function2[B, B, B] = ??? // error | ^ | Double definition: | def foo(x: List[A]): A => A in class Test3 at line 20 and | def foo(x: List[A]): (B, B) => B in class Test3 at line 21 | have matching parameter types. --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:26:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:26:4 ---------------------------------------------------------- 26 | def foo = 2 // error | ^ | Double definition: | val foo: Int in class Test4 at line 25 and | def foo: => Int in class Test4 at line 26 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:31:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:31:4 ---------------------------------------------------------- 31 | val foo = 1 // error | ^ | Double definition: | def foo: => Int in class Test4b at line 30 and | val foo: Int in class Test4b at line 31 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:36:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:36:4 ---------------------------------------------------------- 36 | var foo = 1 // error | ^ | Double definition: | def foo: => Int in class Test4c at line 35 and | var foo: Int in class Test4c at line 36 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:41:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:41:4 ---------------------------------------------------------- 41 | def foo = 2 // error | ^ | Double definition: | var foo: Int in class Test4d at line 40 and | def foo: => Int in class Test4d at line 41 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:55:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:55:4 ---------------------------------------------------------- 55 | def foo(x: List[B]): Function1[B, B] = ??? // error: same jvm signature | ^ | Double definition: | def foo(x: List[A]): A => A in trait Test6 at line 54 and | def foo(x: List[B]): B => B in trait Test6 at line 55 | have the same type after erasure. --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:62:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:62:4 ---------------------------------------------------------- 62 | def foo(x: List[A]): Function2[B, B, B] = ??? // error | ^ | Double definition: | def foo(x: List[A]): A => A in trait Test7 at line 61 and | def foo(x: List[A]): (B, B) => B in trait Test7 at line 62 | have matching parameter types. --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:67:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:67:4 ---------------------------------------------------------- 67 | def foo = 2 // error | ^ | Double definition: | val foo: Int in class Test8 at line 66 and | def foo: => Int in class Test8 at line 67 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:72:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:72:4 ---------------------------------------------------------- 72 | val foo = 1 // error | ^ | Double definition: | def foo: => Int in class Test8b at line 71 and | val foo: Int in class Test8b at line 72 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:77:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:77:4 ---------------------------------------------------------- 77 | var foo = 1 // error | ^ | Double definition: | def foo: => Int in class Test8c at line 76 and | var foo: Int in class Test8c at line 77 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:82:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:82:4 ---------------------------------------------------------- 82 | def foo = 2 // error | ^ | Double definition: | var foo: Int in class Test8d at line 81 and | def foo: => Int in class Test8d at line 82 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:88:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:88:4 ---------------------------------------------------------- 88 | def foo: String // error | ^ | Double definition: | val foo: Int in class Test9 at line 87 and | def foo: => String in class Test9 at line 88 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:92:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:92:4 ---------------------------------------------------------- 92 | def foo: Int // error | ^ | Double definition: | val foo: Int in class Test10 at line 91 and | def foo: => Int in class Test10 at line 92 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:96:4 ------------------------------------------------ +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:96:4 ---------------------------------------------------------- 96 | def foo: String // error | ^ | Double definition: | val foo: Int in class Test11 at line 95 and | def foo: => String in class Test11 at line 96 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:100:4 ----------------------------------------------- +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:100:4 --------------------------------------------------------- 100 | def foo: Int // error | ^ | Double definition: | val foo: Int in class Test12 at line 99 and | def foo: => Int in class Test12 at line 100 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:104:4 ----------------------------------------------- +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:104:4 --------------------------------------------------------- 104 | def foo: String // error | ^ | Double definition: | var foo: Int in class Test13 at line 103 and | def foo: => String in class Test13 at line 104 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:108:4 ----------------------------------------------- +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:108:4 --------------------------------------------------------- 108 | def foo: Int // error | ^ | Double definition: | var foo: Int in class Test14 at line 107 and | def foo: => Int in class Test14 at line 108 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:112:4 ----------------------------------------------- +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:112:4 --------------------------------------------------------- 112 | def foo: String // error | ^ | Double definition: | var foo: Int in class Test15 at line 111 and | def foo: => String in class Test15 at line 112 --- [E120] Duplicate Symbol Error: tests/neg/doubleDefinition.scala:116:4 ----------------------------------------------- +-- [E120] Naming Error: tests/neg/doubleDefinition.scala:116:4 --------------------------------------------------------- 116 | def foo: Int // error | ^ | Double definition: diff --git a/tests/neg/exports.check b/tests/neg/exports.check index e59b11771d2b..13299a35d258 100644 --- a/tests/neg/exports.check +++ b/tests/neg/exports.check @@ -12,21 +12,21 @@ | ^ | non-private method bitmap in class Copier refers to private value printUnit | in its type signature => Copier.this.printUnit.bitmap$ --- [E120] Duplicate Symbol Error: tests/neg/exports.scala:23:33 -------------------------------------------------------- +-- [E120] Naming Error: tests/neg/exports.scala:23:33 ------------------------------------------------------------------ 23 | export printUnit.{stat => _, _} // error: double definition | ^ | Double definition: | def status: => List[String] in class Copier at line 28 and | final def status: => List[String] in class Copier at line 23 | have the same type after erasure. --- [E120] Duplicate Symbol Error: tests/neg/exports.scala:24:20 -------------------------------------------------------- +-- [E120] Naming Error: tests/neg/exports.scala:24:20 ------------------------------------------------------------------ 24 | export scanUnit._ // error: double definition | ^ | Double definition: | final def status: => List[String] in class Copier at line 23 and | final def status: => List[String] in class Copier at line 24 | have the same type after erasure. --- [E120] Duplicate Symbol Error: tests/neg/exports.scala:26:21 -------------------------------------------------------- +-- [E120] Naming Error: tests/neg/exports.scala:26:21 ------------------------------------------------------------------ 26 | export printUnit.status // error: double definition | ^ | Double definition: @@ -43,7 +43,7 @@ | ^^^ | no eligible member foo at this.foo | this.foo.foo cannot be exported because it is already a member of class Foo --- [E120] Duplicate Symbol Error: tests/neg/exports.scala:46:15 -------------------------------------------------------- +-- [E120] Naming Error: tests/neg/exports.scala:46:15 ------------------------------------------------------------------ 46 | export bar._ // error: double definition | ^ | Double definition: diff --git a/tests/neg/i5101.check b/tests/neg/i5101.check index 14032fda3a19..151b8cf2dd4e 100644 --- a/tests/neg/i5101.check +++ b/tests/neg/i5101.check @@ -1,4 +1,4 @@ --- [E006] Unbound Identifier Error: tests/neg/i5101.scala:11:11 -------------------------------------------------------- +-- [E006] Not Found Error: tests/neg/i5101.scala:11:11 ----------------------------------------------------------------- 11 | case A0(_) => // error | ^^ | Not found: A0 diff --git a/tests/neg/i5433.check b/tests/neg/i5433.check index 7f3986ab5553..816c0ee7a15f 100644 --- a/tests/neg/i5433.check +++ b/tests/neg/i5433.check @@ -1,4 +1,4 @@ --- [E137] Reference Error: tests/neg/i5433.scala:17:6 ------------------------------------------------------------------ +-- [E137] Declaration Error: tests/neg/i5433.scala:17:6 ---------------------------------------------------------------- 17 |class Fail extends B with C // error | ^ | class Fail cannot be defined due to a conflict between its parents when diff --git a/tests/neg/i6436.check b/tests/neg/i6436.check index ec431058c1e1..1d1426a4eba2 100644 --- a/tests/neg/i6436.check +++ b/tests/neg/i6436.check @@ -2,7 +2,7 @@ 5 | case '{ StringContext(${Varargs(parts)}: _*) } => // error | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | no implicit argument of type scala.quoted.QuoteContext was found --- [E006] Unbound Identifier Error: tests/neg/i6436.scala:6:34 --------------------------------------------------------- +-- [E006] Not Found Error: tests/neg/i6436.scala:6:34 ------------------------------------------------------------------ 6 | val ps: Seq[Expr[String]] = parts // error | ^^^^^ | Not found: parts diff --git a/tests/neg/i6724.check b/tests/neg/i6724.check index f3665b8b2f79..4dd50236bbcb 100644 --- a/tests/neg/i6724.check +++ b/tests/neg/i6724.check @@ -1,4 +1,4 @@ --- [E008] Member Not Found Error: tests/neg/i6724.scala:7:17 ----------------------------------------------------------- +-- [E008] Not Found Error: tests/neg/i6724.scala:7:17 ------------------------------------------------------------------ 7 | def f(foo: Foo.Baz): Foo[_] = foo // error | ^^^^^^^ | type Baz is not a member of object Foo - did you mean Foo.Bar? diff --git a/tests/neg/i7359-f.check b/tests/neg/i7359-f.check index 2b4d8aa5e208..5cc88336bbf3 100644 --- a/tests/neg/i7359-f.check +++ b/tests/neg/i7359-f.check @@ -1,4 +1,4 @@ --- [E120] Duplicate Symbol Error: tests/neg/i7359-f.scala:1:6 ---------------------------------------------------------- +-- [E120] Naming Error: tests/neg/i7359-f.scala:1:6 -------------------------------------------------------------------- 1 |trait SAMTrait: // error | ^ | Name clash between inherited members: diff --git a/tests/neg/i8032.check b/tests/neg/i8032.check index e5fff3bbf8fc..110c7b0ea410 100644 --- a/tests/neg/i8032.check +++ b/tests/neg/i8032.check @@ -3,7 +3,7 @@ | ^ | Found: (3 : Int) | Required: (1 : Int) | (2 : Int) --- [E008] Member Not Found Error: tests/neg/i8032.scala:3:12 ----------------------------------------------------------- +-- [E008] Not Found Error: tests/neg/i8032.scala:3:12 ------------------------------------------------------------------ 3 |val y = ???.map // error | ^^^^^^^ | value map is not a member of Nothing diff --git a/tests/neg/kinds2.check b/tests/neg/kinds2.check index cd38fc409479..2921c7baf022 100644 --- a/tests/neg/kinds2.check +++ b/tests/neg/kinds2.check @@ -1,4 +1,4 @@ --- [E141] Type Mismatch Error: tests/neg/kinds2.scala:14:4 ------------------------------------------------------------- +-- [E141] Type Error: tests/neg/kinds2.scala:14:4 ---------------------------------------------------------------------- 14 | f[C] // error: missing type parameter(s) | ^ | Missing type parameter for Test.C diff --git a/tests/neg/missing-implicit.check b/tests/neg/missing-implicit.check index 8ac23fee4918..55c48a6345e3 100644 --- a/tests/neg/missing-implicit.check +++ b/tests/neg/missing-implicit.check @@ -1,4 +1,4 @@ --- [E008] Member Not Found Error: tests/neg/missing-implicit.scala:5:25 ------------------------------------------------ +-- [E008] Not Found Error: tests/neg/missing-implicit.scala:5:25 ------------------------------------------------------- 5 | case x :: xs1 if limit > 0 => consume(xs1, limit - x) // error // error | ^^^^^^^ | value > is not a member of T, but could be made available as an extension method. @@ -8,7 +8,7 @@ | import math.Ordered.orderingToOrdered | import math.Ordering.Implicits.infixOrderingOps | --- [E008] Member Not Found Error: tests/neg/missing-implicit.scala:5:51 ------------------------------------------------ +-- [E008] Not Found Error: tests/neg/missing-implicit.scala:5:51 ------------------------------------------------------- 5 | case x :: xs1 if limit > 0 => consume(xs1, limit - x) // error // error | ^^^^^^^ | value - is not a member of T, but could be made available as an extension method. @@ -59,7 +59,7 @@ | | import concurrent.duration.pairIntToDuration | --- [E008] Member Not Found Error: tests/neg/missing-implicit.scala:18:48 ----------------------------------------------- +-- [E008] Not Found Error: tests/neg/missing-implicit.scala:18:48 ------------------------------------------------------ 18 |val d2: scala.concurrent.duration.Duration = 10.days // error | ^^^^^^^ | value days is not a member of Int, but could be made available as an extension method. diff --git a/tests/neg/missing-implicit1.check b/tests/neg/missing-implicit1.check index f04a2c248b69..b78e5b239946 100644 --- a/tests/neg/missing-implicit1.check +++ b/tests/neg/missing-implicit1.check @@ -7,7 +7,7 @@ | | import testObjectInstance.instances.zipOption | --- [E008] Member Not Found Error: tests/neg/missing-implicit1.scala:19:16 ---------------------------------------------- +-- [E008] Not Found Error: tests/neg/missing-implicit1.scala:19:16 ----------------------------------------------------- 19 | List(1, 2, 3).traverse(x => Option(x)) // error | ^^^^^^^^^^^^^^^^^^^^^^ | value traverse is not a member of List[Int], but could be made available as an extension method. @@ -25,7 +25,7 @@ | | import testObjectInstance.instances.zipOption | --- [E008] Member Not Found Error: tests/neg/missing-implicit1.scala:26:16 ---------------------------------------------- +-- [E008] Not Found Error: tests/neg/missing-implicit1.scala:26:16 ----------------------------------------------------- 26 | List(1, 2, 3).first // error | ^^^^^^^^^^^^^^^^^^^ | value first is not a member of List[Int], but could be made available as an extension method. @@ -34,7 +34,7 @@ | | import testObjectInstance.instances.first | --- [E008] Member Not Found Error: tests/neg/missing-implicit1.scala:27:16 ---------------------------------------------- +-- [E008] Not Found Error: tests/neg/missing-implicit1.scala:27:16 ----------------------------------------------------- 27 | List(1, 2, 3).second // error | ^^^^^^^^^^^^^^^^^^^^ | value second is not a member of List[Int], but could be made available as an extension method. @@ -43,7 +43,7 @@ | | import testObjectInstance.instances.listExtension | --- [E008] Member Not Found Error: tests/neg/missing-implicit1.scala:28:17 ---------------------------------------------- +-- [E008] Not Found Error: tests/neg/missing-implicit1.scala:28:17 ----------------------------------------------------- 28 | Array(1, 2, 3).first // error, no hint | ^^^^^^^^^^^^^^^^^^^^ | value first is not a member of Array[Int] @@ -56,7 +56,7 @@ | | import instances.zipOption | --- [E008] Member Not Found Error: tests/neg/missing-implicit1.scala:46:16 ---------------------------------------------- +-- [E008] Not Found Error: tests/neg/missing-implicit1.scala:46:16 ----------------------------------------------------- 46 | List(1, 2, 3).traverse(x => Option(x)) // error | ^^^^^^^^^^^^^^^^^^^^^^ | value traverse is not a member of List[Int], but could be made available as an extension method. diff --git a/tests/neg/mixin-forwarder-clash1.check b/tests/neg/mixin-forwarder-clash1.check index 7c007dc62788..f5a10c40202f 100644 --- a/tests/neg/mixin-forwarder-clash1.check +++ b/tests/neg/mixin-forwarder-clash1.check @@ -1,4 +1,4 @@ --- [E120] Duplicate Symbol Error: tests/neg/mixin-forwarder-clash1.scala:15:6 ------------------------------------------ +-- [E120] Naming Error: tests/neg/mixin-forwarder-clash1.scala:15:6 ---------------------------------------------------- 15 |class Bar2 extends Bar1 with Two[Foo] // error | ^ | Name clash between inherited members: diff --git a/tests/neg/mixin-forwarder-clash2.check b/tests/neg/mixin-forwarder-clash2.check index 422782833a36..9c3b23847e1f 100644 --- a/tests/neg/mixin-forwarder-clash2.check +++ b/tests/neg/mixin-forwarder-clash2.check @@ -1,5 +1,5 @@ --- [E120] Duplicate Symbol Error: tests/neg/mixin-forwarder-clash2/B_2.scala:1:6 --------------------------------------- +-- [E120] Naming Error: tests/neg/mixin-forwarder-clash2/B_2.scala:1:6 ------------------------------------------------- 1 |class Bar2 extends Bar1 with Two[Foo] // error | ^ | Name clash between inherited members: diff --git a/tests/neg/module-class-name.check b/tests/neg/module-class-name.check index a46c5382e65c..70d944ee4330 100644 --- a/tests/neg/module-class-name.check +++ b/tests/neg/module-class-name.check @@ -18,7 +18,7 @@ | ^ | Found: Test.C.type | Required: Int --- [E008] Member Not Found Error: tests/neg/module-class-name.scala:15:4 ----------------------------------------------- +-- [E008] Not Found Error: tests/neg/module-class-name.scala:15:4 ------------------------------------------------------ 15 | C.foo // error: value foo is not a member of object Test.C | ^^^^^ | value foo is not a member of object Test.C diff --git a/tests/neg/multi-file-error.check b/tests/neg/multi-file-error.check index ad6a3f3b53be..bf3547333361 100644 --- a/tests/neg/multi-file-error.check +++ b/tests/neg/multi-file-error.check @@ -1,10 +1,10 @@ --- [E006] Unbound Identifier Error: tests/neg/multi-file-error/A.scala:2:2 --------------------------------------------- +-- [E006] Not Found Error: tests/neg/multi-file-error/A.scala:2:2 ------------------------------------------------------ 2 | foo() // error | ^^^ | Not found: foo longer explanation available when compiling with `-explain` --- [E006] Unbound Identifier Error: tests/neg/multi-file-error/B.scala:2:2 --------------------------------------------- +-- [E006] Not Found Error: tests/neg/multi-file-error/B.scala:2:2 ------------------------------------------------------ 2 | bar() // error | ^^^ | Not found: bar diff --git a/tests/neg/name-hints.check b/tests/neg/name-hints.check index 8fb70a5526f8..324416d08c96 100644 --- a/tests/neg/name-hints.check +++ b/tests/neg/name-hints.check @@ -1,72 +1,72 @@ --- [E008] Member Not Found Error: tests/neg/name-hints.scala:6:15 ------------------------------------------------------ +-- [E008] Not Found Error: tests/neg/name-hints.scala:6:15 ------------------------------------------------------------- 6 | val x1 = Int.maxvalue // error | ^^^^^^^^^^^^ | value maxvalue is not a member of object Int - did you mean Int.MaxValue? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:7:15 ------------------------------------------------------ +-- [E008] Not Found Error: tests/neg/name-hints.scala:7:15 ------------------------------------------------------------- 7 | val x2 = Int.MxValue // error | ^^^^^^^^^^^ | value MxValue is not a member of object Int - did you mean Int.MaxValue? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:8:15 ------------------------------------------------------ +-- [E008] Not Found Error: tests/neg/name-hints.scala:8:15 ------------------------------------------------------------- 8 | val x3 = Int.MaxxValue // error | ^^^^^^^^^^^^^ | value MaxxValue is not a member of object Int - did you mean Int.MaxValue? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:10:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:10:13 ------------------------------------------------------------ 10 | val d1 = O.abcd // error | ^^^^^^ | value abcd is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:11:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:11:13 ------------------------------------------------------------ 11 | val d2 = O.abc // error | ^^^^^ | value abc is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:12:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:12:13 ------------------------------------------------------------ 12 | val d3 = O.ab // error, no hint since distance = 3 > 2 = length | ^^^^ | value ab is not a member of object O --- [E008] Member Not Found Error: tests/neg/name-hints.scala:13:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:13:13 ------------------------------------------------------------ 13 | val s1 = O.Abcde // error | ^^^^^^^ | value Abcde is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:14:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:14:13 ------------------------------------------------------------ 14 | val s3 = O.AbCde // error | ^^^^^^^ | value AbCde is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:15:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:15:13 ------------------------------------------------------------ 15 | val s3 = O.AbCdE // error | ^^^^^^^ | value AbCdE is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:16:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:16:13 ------------------------------------------------------------ 16 | val s3 = O.AbCDE // error, no hint | ^^^^^^^ | value AbCDE is not a member of object O --- [E008] Member Not Found Error: tests/neg/name-hints.scala:17:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:17:13 ------------------------------------------------------------ 17 | val a1 = O.abcde0 // error | ^^^^^^^^ | value abcde0 is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:18:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:18:13 ------------------------------------------------------------ 18 | val a2 = O.abcde00 // error | ^^^^^^^^^ | value abcde00 is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:19:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:19:13 ------------------------------------------------------------ 19 | val a3 = O.abcde000 // error | ^^^^^^^^^^ | value abcde000 is not a member of object O - did you mean O.abcde? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:20:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:20:13 ------------------------------------------------------------ 20 | val a4 = O.abcde0000 // error, no hint | ^^^^^^^^^^^ | value abcde0000 is not a member of object O --- [E008] Member Not Found Error: tests/neg/name-hints.scala:22:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:22:13 ------------------------------------------------------------ 22 | val y1 = O.x // error, no hint | ^^^ | value x is not a member of object O --- [E008] Member Not Found Error: tests/neg/name-hints.scala:23:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:23:13 ------------------------------------------------------------ 23 | val y2 = O.xY // error | ^^^^ | value xY is not a member of object O - did you mean O.xy? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:24:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:24:13 ------------------------------------------------------------ 24 | val y3 = O.xyz // error | ^^^^^ | value xyz is not a member of object O - did you mean O.xy? --- [E008] Member Not Found Error: tests/neg/name-hints.scala:25:13 ----------------------------------------------------- +-- [E008] Not Found Error: tests/neg/name-hints.scala:25:13 ------------------------------------------------------------ 25 | val y2 = O.XY // error, no hint | ^^^^ | value XY is not a member of object O diff --git a/tests/neg/t6124.check b/tests/neg/t6124.check index 098f453913c1..9c7498d60f88 100644 --- a/tests/neg/t6124.check +++ b/tests/neg/t6124.check @@ -54,11 +54,11 @@ 12 | def tooSmall = 1.0E-325 // error | ^^^^^^^^ | number too small --- [E008] Member Not Found Error: tests/neg/t6124.scala:18:14 ---------------------------------------------------------- +-- [E008] Not Found Error: tests/neg/t6124.scala:18:14 ----------------------------------------------------------------- 18 | val pi2 = 3._1415F // error | ^^^^^^^^ | value _1415F is not a member of Int --- [E006] Unbound Identifier Error: tests/neg/t6124.scala:21:11 -------------------------------------------------------- +-- [E006] Not Found Error: tests/neg/t6124.scala:21:11 ----------------------------------------------------------------- 21 | val x1 = _52 // error | ^^^ | Not found: _52 diff --git a/tests/run-staging/i7142.scala b/tests/run-staging/i7142.scala index aca76b331a42..ff4bd6597703 100644 --- a/tests/run-staging/i7142.scala +++ b/tests/run-staging/i7142.scala @@ -7,7 +7,7 @@ object Test { def main(args: Array[String]): Unit = try run {returning('{ { (x: Int) => ${ throwReturn('x) }} apply 0 })} catch { - case ex: dotty.tools.dotc.reporting.messages.Error => + case ex: dotty.tools.dotc.reporting.Diagnostic.Error => assert(ex.getMessage == "While expanding a macro, a reference to value x was used outside the scope where it was defined", ex.getMessage) } } From dd8af225461f04f6719726b267047faa68e1a357 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 21:27:23 +0100 Subject: [PATCH 10/13] Refactoring of message filtering The previous pipeline forgot to filter out tags in most situations --- .../tools/dotc/printing/Formatting.scala | 4 +- .../tools/dotc/printing/PlainPrinter.scala | 2 +- .../dotc/reporting/ConsoleReporter.scala | 10 ++-- .../tools/dotc/reporting/Diagnostic.scala | 53 +++---------------- .../reporting/HideNonSensicalMessages.scala | 2 +- .../dotty/tools/dotc/reporting/Message.scala | 38 ++++++++++++- .../dotc/reporting/MessageRendering.scala | 4 +- .../dotty/tools/dotc/typer/Applications.scala | 4 +- .../src/dotty/tools/repl/ReplDriver.scala | 2 +- .../dotc/reporting/ErrorMessagesTest.scala | 2 +- .../tools/dotc/reporting/TestReporter.scala | 6 +-- .../dotty/tools/dottydoc/DottyDocTest.scala | 2 +- .../languageserver/DottyLanguageServer.scala | 5 +- sbt-bridge/src/xsbt/DelegatingReporter.java | 16 +++--- 14 files changed, 73 insertions(+), 77 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index 025eace2e58c..c3d4fea1b7ad 100644 --- a/compiler/src/dotty/tools/dotc/printing/Formatting.scala +++ b/compiler/src/dotty/tools/dotc/printing/Formatting.scala @@ -6,7 +6,7 @@ import Texts._, Types._, Flags._, Symbols._, Contexts._ import collection.mutable import Decorators._ import scala.util.control.NonFatal -import reporting.Diagnostic +import reporting.Message import util.DiffUtil import Highlighting._ @@ -88,7 +88,7 @@ object Formatting { } private def wrapNonSensical(arg: Any, str: String)(implicit ctx: Context): String = { - import Diagnostic._ + import Message._ def isSensical(arg: Any): Boolean = arg match { case tpe: Type => tpe.exists && !tpe.isErroneous diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 468358700758..50bffd7e6d23 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -170,7 +170,7 @@ class PlainPrinter(_ctx: Context) extends Printer { (" <: " ~ toText(bound) provided !bound.isAny) }.close case tp: ErrorType => - s"" + s"" case tp: WildcardType => if (tp.optBounds.exists) "" else "" case NoType => diff --git a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 0a0ebad3b69d..6a7d21e827eb 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -23,19 +23,19 @@ class ConsoleReporter( def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = { val didPrint = dia match { case dia: Error => - printMessage(messageAndPos(dia.contained, dia.pos, diagnosticLevel(dia))) + printMessage(messageAndPos(dia.msg, dia.pos, diagnosticLevel(dia))) if (ctx.settings.Xprompt.value) Reporter.displayPrompt(reader, writer) true case dia: ConditionalWarning if !dia.enablingOption.value => false case dia => - printMessage(messageAndPos(dia.contained, dia.pos, diagnosticLevel(dia))) + printMessage(messageAndPos(dia.msg, dia.pos, diagnosticLevel(dia))) true } - if (didPrint && ctx.shouldExplain(dia)) - printMessage(explanation(dia.contained)) - else if (didPrint && dia.contained.explanation.nonEmpty) + if (didPrint && shouldExplain(dia)) + printMessage(explanation(dia.msg)) + else if (didPrint && dia.msg.explanation.nonEmpty) printMessage("\nlonger explanation available when compiling with `-explain`") } diff --git a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index 10558f11182f..865b3a6a5427 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -10,18 +10,9 @@ import interfaces.Diagnostic.{ERROR, INFO, WARNING} import java.util.Optional object Diagnostic: - val nonSensicalStartTag: String = "" - val nonSensicalEndTag: String = "" - implicit class MessageContext(val c: Context) extends AnyVal { - def shouldExplain(dia: Diagnostic): Boolean = { - implicit val ctx = c - dia.contained.explanation match { - case "" => false - case _ => ctx.settings.explain.value - } - } - } + def shouldExplain(dia: Diagnostic)(using ctx: Context): Boolean = + dia.msg.explanation.nonEmpty && ctx.settings.explain.value // `Diagnostics to be consumed by `Reporter` ---------------------- // class Error( @@ -86,44 +77,14 @@ object Diagnostic: } class Diagnostic( - val contained: Message, + val msg: Message, val pos: SourcePosition, val level: Int -) extends Exception with interfaces.Diagnostic { - import Diagnostic._ - private var myMsg: String = null - private var myIsNonSensical: Boolean = false - private var myContained: Message = null - +) extends Exception with interfaces.Diagnostic: override def position: Optional[interfaces.SourcePosition] = if (pos.exists && pos.source.exists) Optional.of(pos) else Optional.empty() + override def message: String = msg.message - /** The message to report */ - def message: String = { - if (myMsg == null) { - myMsg = contained.msg.replaceAll("\u001B\\[[;\\d]*m", "") - if (myMsg.contains(nonSensicalStartTag)) { - myIsNonSensical = true - // myMsg might be composed of several d"..." invocations -> nested - // nonsensical tags possible - myMsg = - myMsg - .replaceAllLiterally(nonSensicalStartTag, "") - .replaceAllLiterally(nonSensicalEndTag, "") - } - } - myMsg - } - - /** A message is non-sensical if it contains references to - * tags. Such tags are inserted by the error diagnostic framework if a - * message contains references to internally generated error types. Normally - * we want to suppress error messages referring to types like this because - * they look weird and are normally follow-up errors to something that was - * diagnosed before. - */ - def isNonSensical: Boolean = { message; myIsNonSensical } - - override def toString: String = s"$getClass at $pos: ${message}" + override def toString: String = s"$getClass at $pos: $message" override def getMessage(): String = message -} +end Diagnostic diff --git a/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala b/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala index 2ed75a1173c3..0e6fe3fd8bb7 100644 --- a/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/HideNonSensicalMessages.scala @@ -13,7 +13,7 @@ trait HideNonSensicalMessages extends Reporter { */ override def isHidden(dia: Diagnostic)(implicit ctx: Context): Boolean = super.isHidden(dia) || { - dia.isNonSensical && + dia.msg.isNonSensical && hasErrors && // if there are no errors yet, report even if diagnostic is non-sensical !ctx.settings.YshowSuppressedErrors.value } diff --git a/compiler/src/dotty/tools/dotc/reporting/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala index c9b6abe3f76e..5d44bbddeded 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -7,6 +7,9 @@ import util.SourcePosition import messages._ object Message { + val nonSensicalStartTag: String = "" + val nonSensicalEndTag: String = "" + /** This implicit conversion provides a fallback for error messages that have * not yet been ported to the new scheme. Comment out this `implicit def` to * see where old errors still exist @@ -32,6 +35,7 @@ object Message { * used to reference documentation online */ abstract class Message(val errorId: ErrorMessageID) { self => + import Message._ /** The `msg` contains the diagnostic message e.g: * @@ -39,9 +43,10 @@ abstract class Message(val errorId: ErrorMessageID) { self => * > found: Int * * This message will be placed underneath the position given by the enclosing - * `Diagnostic` + * `Diagnostic`. The message is given in raw form, with possible embedded + * tags. */ - def msg: String + protected def msg: String /** The kind of the error message is something like "Syntax" or "Type * Mismatch" @@ -54,6 +59,35 @@ abstract class Message(val errorId: ErrorMessageID) { self => */ def explanation: String + private var myMsg: String | Null = null + private var myIsNonSensical: Boolean = false + + /** The message with potential embedded tags */ + def rawMessage = message + + /** The message to report. tags are filtered out */ + def message: String = + if myMsg == null then + myMsg = + if msg.contains(nonSensicalStartTag) then + myIsNonSensical = true + // myMsg might be composed of several d"..." invocations -> nested + // nonsensical tags possible + msg + .replaceAllLiterally(nonSensicalStartTag, "") + .replaceAllLiterally(nonSensicalEndTag, "") + else msg + myMsg + + /** A message is non-sensical if it contains references to + * tags. Such tags are inserted by the error diagnostic framework if a + * message contains references to internally generated error types. Normally + * we want to suppress error messages referring to types like this because + * they look weird and are normally follow-up errors to something that was + * diagnosed before. + */ + def isNonSensical: Boolean = { message; myIsNonSensical } + /** The implicit `Context` in messages is a large thing that we don't want * persisted. This method gets around that by duplicating the message, * forcing its `msg` and `explanation` vals and dropping the implicit context diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index fe908736938b..c37226d29b1a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -151,10 +151,10 @@ trait MessageRendering { val pos1 = pos.nonInlined val (srcBefore, srcAfter, offset) = sourceLines(pos1, diagnosticLevel) val marker = columnMarker(pos1, offset, diagnosticLevel) - val err = errorMsg(pos1, msg.msg, offset) + val err = errorMsg(pos1, msg.message, offset) sb.append((srcBefore ::: marker :: err :: outer(pos, " " * (offset - 1)) ::: srcAfter).mkString(EOL)) } - else sb.append(msg.msg) + else sb.append(msg.message) sb.toString } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 9fd0709c8048..f3035ee5c249 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1066,8 +1066,8 @@ trait Applications extends Compatibility { */ def saysNotFound(state: TyperState, memberName: Name)(using Context): Boolean = state.reporter.pendingMessages match - case msg :: Nil => - msg.contained match + case dia :: Nil => + dia.msg match case msg: NotFoundMsg => memberName.isEmpty || msg.name == memberName case _ => false case _ => false diff --git a/compiler/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 8ee9730c331a..2e15177477d8 100644 --- a/compiler/src/dotty/tools/repl/ReplDriver.scala +++ b/compiler/src/dotty/tools/repl/ReplDriver.scala @@ -381,7 +381,7 @@ class ReplDriver(settings: Array[String], /** Render messages using the `MessageRendering` trait */ private def renderMessage(dia: Diagnostic): Context => String = - messageRenderer.messageAndPos(dia.contained, dia.pos, messageRenderer.diagnosticLevel(dia))(_) + messageRenderer.messageAndPos(dia.msg, dia.pos, messageRenderer.diagnosticLevel(dia))(_) /** Output errors to `out` */ private def displayErrors(errs: Seq[Diagnostic])(implicit state: State): State = { diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala index b50ac28bbf96..59b81ecf3a32 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala @@ -36,7 +36,7 @@ trait ErrorMessagesTest extends DottyTest { if (!runCtx.reporter.hasErrors) new EmptyReport else { val rep = runCtx.reporter.asInstanceOf[StoreReporter] - val msgs = rep.removeBufferedMessages(runCtx).map(_.contained).reverse + val msgs = rep.removeBufferedMessages(runCtx).map(_.msg).reverse new Report(msgs, runCtx) } } diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala index bec27c93c033..c935b579b234 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala @@ -54,7 +54,7 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M /** Prints the message with the given position indication. */ def printMessageAndPos(dia: Diagnostic, extra: String)(implicit ctx: Context): Unit = { - val msg = messageAndPos(dia.contained, dia.pos, diagnosticLevel(dia)) + val msg = messageAndPos(dia.msg, dia.pos, diagnosticLevel(dia)) val extraInfo = inlineInfo(dia.pos) if (dia.level >= logLevel) { @@ -69,7 +69,7 @@ extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with M override def doReport(dia: Diagnostic)(implicit ctx: Context): Unit = { // Here we add extra information that we should know about the error message - val extra = dia.contained match { + val extra = dia.msg match { case pm: PatternMatchExhaustivity => s": ${pm.uncovered}" case _ => "" } @@ -127,7 +127,7 @@ object TestReporter { /** Prints the message with the given position indication in a simplified manner */ override def printMessageAndPos(dia: Diagnostic, extra: String)(implicit ctx: Context): Unit = { def report() = { - val msg = s"${dia.pos.line + 1}: " + dia.contained.kind + extra + val msg = s"${dia.pos.line + 1}: " + dia.msg.kind + extra val extraInfo = inlineInfo(dia.pos) writer.println(msg) diff --git a/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala b/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala index bd7251cd06b7..d12abdbc7973 100644 --- a/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala +++ b/doc-tool/test/dotty/tools/dottydoc/DottyDocTest.scala @@ -54,7 +54,7 @@ trait DottyDocTest extends MessageRendering { System.err.println("reporter had errors:") ctx.reporter.removeBufferedMessages.foreach { msg => System.err.println { - messageAndPos(msg.contained, msg.pos, diagnosticLevel(msg)) + messageAndPos(msg.msg, msg.pos, diagnosticLevel(msg)) } } } diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index b3e24d456b2a..efdcdaf07808 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -709,12 +709,13 @@ object DottyLanguageServer { } } - val message = dia.contained + val message = dia.msg if (displayMessage(message, dia.pos.source)) { val code = message.errorId.errorNumber.toString range(dia.pos).map(r => new lsp4j.Diagnostic( - r, dia.message, severity(dia.level), /*source =*/ "", code)) + r, dia.message.replaceAll("\u001B\\[[;\\d]*m", ""), + severity(dia.level), /*source =*/ "", code)) } else { None } diff --git a/sbt-bridge/src/xsbt/DelegatingReporter.java b/sbt-bridge/src/xsbt/DelegatingReporter.java index 618e76a08bf0..536a08d31b96 100644 --- a/sbt-bridge/src/xsbt/DelegatingReporter.java +++ b/sbt-bridge/src/xsbt/DelegatingReporter.java @@ -57,9 +57,9 @@ public void printSummary(Context ctx) { delegate.printSummary(); } - public void doReport(dotty.tools.dotc.reporting.Diagnostic cont, Context ctx) { + public void doReport(dotty.tools.dotc.reporting.Diagnostic dia, Context ctx) { Severity severity; - switch (cont.level()) { + switch (dia.level()) { case Diagnostic.ERROR: severity = Severity.Error; break; @@ -70,12 +70,12 @@ public void doReport(dotty.tools.dotc.reporting.Diagnostic cont, Context ctx) { severity = Severity.Info; break; default: - throw new IllegalArgumentException("Bad diagnostic level: " + cont.level()); + throw new IllegalArgumentException("Bad diagnostic level: " + dia.level()); } Position position; - if (cont.pos().exists()) { - SourcePosition pos = cont.pos(); + if (dia.pos().exists()) { + SourcePosition pos = dia.pos(); SourceFile src = pos.source(); position = new Position() { public Optional sourceFile() { @@ -123,10 +123,10 @@ public Optional pointerSpace() { position = noPosition; } - Message message = cont.contained(); + Message message = dia.msg(); StringBuilder rendered = new StringBuilder(); - rendered.append(messageAndPos(message, cont.pos(), diagnosticLevel(cont), ctx)); - boolean shouldExplain = new dotty.tools.dotc.reporting.Diagnostic.MessageContext(ctx).shouldExplain(cont); + rendered.append(messageAndPos(message, dia.pos(), diagnosticLevel(dia), ctx)); + boolean shouldExplain = dotty.tools.dotc.reporting.Diagnostic.shouldExplain(dia, ctx); if (shouldExplain && !message.explanation().isEmpty()) { rendered.append(explanation(message, ctx)); } From 9277ae651b36b7d3c1cdad3acd20f7dc51567ed2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 22:08:48 +0100 Subject: [PATCH 11/13] Move message string replacement back to diagnostic --- compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala | 3 ++- .../src/dotty/tools/languageserver/DottyLanguageServer.scala | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index 865b3a6a5427..1ab74c571697 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -83,7 +83,8 @@ class Diagnostic( ) extends Exception with interfaces.Diagnostic: override def position: Optional[interfaces.SourcePosition] = if (pos.exists && pos.source.exists) Optional.of(pos) else Optional.empty() - override def message: String = msg.message + override def message: String = + msg.message.replaceAll("\u001B\\[[;\\d]*m", "") override def toString: String = s"$getClass at $pos: $message" override def getMessage(): String = message diff --git a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala index efdcdaf07808..c6314d7a3cd6 100644 --- a/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala +++ b/language-server/src/dotty/tools/languageserver/DottyLanguageServer.scala @@ -714,8 +714,7 @@ object DottyLanguageServer { val code = message.errorId.errorNumber.toString range(dia.pos).map(r => new lsp4j.Diagnostic( - r, dia.message.replaceAll("\u001B\\[[;\\d]*m", ""), - severity(dia.level), /*source =*/ "", code)) + r, dia.message, severity(dia.level), /*source =*/ "", code)) } else { None } From 3d21fc54b466c46d547b7a47b9d78dce51ded5ae Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 25 Mar 2020 22:24:26 +0100 Subject: [PATCH 12/13] Partial revert of pattern matching message kinds --- compiler/src/dotty/tools/dotc/reporting/messages.scala | 6 ++++-- tests/patmat/i4225b.check | 2 +- tests/patmat/null.check | 4 ++-- tests/patmat/t4661.check | 4 ++-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 494d0f6d4f60..24bebb6a97c2 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -806,7 +806,8 @@ object messages { } class PatternMatchExhaustivity(uncoveredFn: => String)(implicit ctx: Context) - extends PatternMatchMsg(PatternMatchExhaustivityID) { + extends Message(PatternMatchExhaustivityID) { + val kind = "Pattern Match Exhaustivity" lazy val uncovered = uncoveredFn lazy val msg: String = em"""|${hl("match")} may not be exhaustive. @@ -834,7 +835,8 @@ object messages { } class MatchCaseUnreachable()(implicit ctx: Context) - extends PatternMatchMsg(MatchCaseUnreachableID) { + extends Message(MatchCaseUnreachableID) { + val kind = "Match case Unreachable" lazy val msg: String = "Unreachable case" lazy val explanation: String = "" } diff --git a/tests/patmat/i4225b.check b/tests/patmat/i4225b.check index e87f2069a72c..b2ced2a124af 100644 --- a/tests/patmat/i4225b.check +++ b/tests/patmat/i4225b.check @@ -1 +1 @@ -10: Only null matched \ No newline at end of file +10: Pattern Match diff --git a/tests/patmat/null.check b/tests/patmat/null.check index 2ddb0e15753f..da081e6b56c0 100644 --- a/tests/patmat/null.check +++ b/tests/patmat/null.check @@ -1,4 +1,4 @@ 6: Match case Unreachable -13: Only null matched +13: Pattern Match 18: Match case Unreachable -20: Only null matched +20: Pattern Match diff --git a/tests/patmat/t4661.check b/tests/patmat/t4661.check index 53a5baa3ca76..362a98d0a870 100644 --- a/tests/patmat/t4661.check +++ b/tests/patmat/t4661.check @@ -9,7 +9,7 @@ 37: Match case Unreachable 38: Match case Unreachable 39: Match case Unreachable -40: Only null matched +40: Pattern Match 46: Match case Unreachable 52: Match case Unreachable -59: Only null matched +59: Pattern Match From a535680830a2ca03b90a9080a49ca869f1e6425c Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Thu, 26 Mar 2020 10:23:14 +0100 Subject: [PATCH 13/13] Turn defined messages and explanations into protected defs Caching is done at a central point in class `Message` where also `` tags are dropped. --- .../dotty/tools/dotc/reporting/Message.scala | 57 +- .../dotty/tools/dotc/reporting/messages.scala | 645 +++++++++--------- .../dotc/reporting/TestMessageLaziness.scala | 4 +- 3 files changed, 351 insertions(+), 355 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/reporting/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala index 5d44bbddeded..25343fb26419 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -48,36 +48,39 @@ abstract class Message(val errorId: ErrorMessageID) { self => */ protected def msg: String - /** The kind of the error message is something like "Syntax" or "Type - * Mismatch" + /** The kind of the error message, e.g. "Syntax" or "Type Mismatch". + * This will be printed as "$kind Error", "$kind Warning", etc, on the first + * line of the message. */ def kind: String /** The explanation should provide a detailed description of why the error * occurred and use examples from the user's own code to illustrate how to - * avoid these errors. + * avoid these errors. It might contain embedded tags. */ - def explanation: String + protected def explain: String private var myMsg: String | Null = null private var myIsNonSensical: Boolean = false + private def dropNonSensical(msg: String): String = + if msg.contains(nonSensicalStartTag) then + myIsNonSensical = true + // myMsg might be composed of several d"..." invocations -> nested + // nonsensical tags possible + msg + .replaceAllLiterally(nonSensicalStartTag, "") + .replaceAllLiterally(nonSensicalEndTag, "") + else msg + /** The message with potential embedded tags */ def rawMessage = message /** The message to report. tags are filtered out */ - def message: String = - if myMsg == null then - myMsg = - if msg.contains(nonSensicalStartTag) then - myIsNonSensical = true - // myMsg might be composed of several d"..." invocations -> nested - // nonsensical tags possible - msg - .replaceAllLiterally(nonSensicalStartTag, "") - .replaceAllLiterally(nonSensicalEndTag, "") - else msg - myMsg + lazy val message: String = dropNonSensical(msg) + + /** The explanation to report. tags are filtered out */ + lazy val explanation: String = dropNonSensical(explain) /** A message is non-sensical if it contains references to * tags. Such tags are inserted by the error diagnostic framework if a @@ -94,30 +97,30 @@ abstract class Message(val errorId: ErrorMessageID) { self => * that was captured in the original message. */ def persist: Message = new Message(errorId) { - val kind = self.kind - val msg = self.msg - val explanation = self.explanation + val kind = self.kind + val msg = self.msg + val explain = self.explain } def append(suffix: => String): Message = mapMsg(_ ++ suffix) def mapMsg(f: String => String): Message = new Message(errorId): - val kind = self.kind - lazy val msg = f(self.msg) - lazy val explanation = self.explanation + val kind = self.kind + def msg = f(self.msg) + def explain = self.explain def appendExplanation(suffix: => String): Message = new Message(errorId): - val kind = self.kind - lazy val msg = self.msg - lazy val explanation = self.explanation ++ suffix + val kind = self.kind + def msg = self.msg + def explain = self.explain ++ suffix override def toString = msg } /** The fallback `Message` containing no explanation and having no `kind` */ class NoExplanation(msgFn: => String) extends Message(ErrorMessageID.NoExplanationID) { - lazy val msg: String = msgFn - val explanation: String = "" + def msg: String = msgFn + def explain: String = "" val kind: String = "" override def toString(): String = msg diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 24bebb6a97c2..0b5f1c40980c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -45,40 +45,40 @@ object messages { |${Blue("http://docs.scala-lang.org/overviews/core/implicit-classes.html")}""" abstract class SyntaxMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Syntax" + def kind = "Syntax" abstract class TypeMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Type" + def kind = "Type" abstract class TypeMismatchMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Type Mismatch" + def kind = "Type Mismatch" abstract class NamingMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Naming" + def kind = "Naming" abstract class DeclarationMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Declaration" + def kind = "Declaration" /** A simple not found message (either for idents, or member selection. * Messages of this class are sometimes dropped in favor of other, more * specific messages. */ abstract class NotFoundMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Not Found" + def kind = "Not Found" def name: Name abstract class PatternMatchMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Pattern Match" + def kind = "Pattern Match" abstract class CyclicMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Cyclic" + def kind = "Cyclic" abstract class ReferenceMsg(errorId: ErrorMessageID) extends Message(errorId): - val kind = "Reference" + def kind = "Reference" abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) extends SyntaxMsg(EmptyCatchOrFinallyBlockID) { - lazy val explanation: String = { + def explain = { val tryString = tryBody match { case Block(Nil, untpd.EmptyTree) => "{}" case _ => tryBody.show @@ -114,23 +114,23 @@ object messages { class EmptyCatchBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchBlockID) { - lazy val msg: String = + def msg = em"""|The ${hl("catch")} block does not contain a valid expression, try |adding a case like - ${hl("case e: Exception =>")} to the block""" } class EmptyCatchAndFinallyBlock(tryBody: untpd.Tree)(implicit ctx: Context) extends EmptyCatchOrFinallyBlock(tryBody, EmptyCatchAndFinallyBlockID) { - lazy val msg: String = + def msg = em"""|A ${hl("try")} without ${hl("catch")} or ${hl("finally")} is equivalent to putting |its body in a block; no exceptions are handled.""" } class DeprecatedWithOperator()(implicit ctx: Context) extends SyntaxMsg(DeprecatedWithOperatorID) { - lazy val msg: String = + def msg = em"""${hl("with")} as a type operator has been deprecated; use ${hl("&")} instead""" - lazy val explanation: String = + def explain = em"""|Dotty introduces intersection types - ${hl("&")} types. These replace the |use of the ${hl("with")} keyword. There are a few differences in |semantics between intersection types and using ${hl("with")}.""" @@ -138,10 +138,10 @@ object messages { class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) extends SyntaxMsg(CaseClassMissingParamListID) { - lazy val msg: String = + def msg = em"""|A ${hl("case class")} must have at least one parameter list""" - lazy val explanation: String = + def explain = em"""|${cdef.name} must have at least one parameter list, if you would rather |have a singleton representation of ${cdef.name}, use a "${hl("case object")}". |Or, add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""" @@ -153,7 +153,7 @@ object messages { pt: Type) (implicit ctx: Context) extends TypeMsg(AnonymousFunctionMissingParamTypeID) { - lazy val msg: String = { + def msg = { val ofFun = if (MethodType.syntheticParamNames(args.length + 1) contains param.name) i" of expanded function:\n$tree" @@ -169,13 +169,13 @@ object messages { |I could not infer the type of the parameter ${param.name}$ofFun.$inferred""" } - lazy val explanation: String = "" + def explain = "" } class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) extends SyntaxMsg(WildcardOnTypeArgumentNotAllowedOnNewID) { - lazy val msg: String = "Type argument must be fully defined" - lazy val explanation: String = + def msg = "Type argument must be fully defined" + def explain = val code1: String = """ |object TyperDemo { @@ -206,9 +206,9 @@ object messages { // Type Errors ------------------------------------------------------------ // class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) extends NamingMsg(DuplicateBindID) { - lazy val msg: String = em"duplicate pattern variable: ${bind.name}" + def msg = em"duplicate pattern variable: ${bind.name}" - lazy val explanation: String = { + def explain = { val pat = tree.pat.show val guard = tree.guard match { case untpd.EmptyTree => "" @@ -232,8 +232,8 @@ object messages { class MissingIdent(tree: untpd.Ident, treeKind: String, val name: Name)(implicit ctx: Context) extends NotFoundMsg(MissingIdentID) { - lazy val msg: String = em"Not found: $treeKind$name" - lazy val explanation: String = { + def msg = em"Not found: $treeKind$name" + def explain = { em"""|The identifier for `$treeKind$name` is not bound, that is, |no declaration for this identifier can be found. |That can happen, for example, if `$name` or its declaration has either been @@ -263,7 +263,7 @@ object messages { case tp: TypeVar => apply(tp.stripTypeVar) case _ => mapOver(tp) - lazy val msg: String = + def msg = val found1 = reported(found) reported.setVariance(-1) val expected1 = reported(expected) @@ -284,14 +284,14 @@ object messages { |Required: $expectedStr""".stripMargin + whereSuffix + err.whyNoMatchStr(found, expected) + postScript - lazy val explanation: String = "" + def explain = "" end TypeMismatch class NotAMember(site: Type, val name: Name, selected: String, addendum: => String = "")(implicit ctx: Context) extends NotFoundMsg(NotAMemberID) { //println(i"site = $site, decls = ${site.decls}, source = ${site.widen.typeSymbol.sourceFile}") //DEBUG - lazy val msg: String = { + def msg = { import core.Flags._ val maxDist = 3 // maximal number of differences to be considered for a hint val missing = name.show @@ -343,14 +343,14 @@ object messages { ex"$selected $name is not a member of ${site.widen}$finalAddendum" } - lazy val explanation: String = "" + def explain = "" } class EarlyDefinitionsNotSupported()(implicit ctx: Context) extends SyntaxMsg(EarlyDefinitionsNotSupportedID) { - lazy val msg: String = "Early definitions are not supported; use trait parameters instead" + def msg = "Early definitions are not supported; use trait parameters instead" - lazy val explanation: String = { + def explain = { val code1 = """|trait Logging { | val f: File @@ -393,9 +393,9 @@ object messages { class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) extends SyntaxMsg(TopLevelImplicitClassID) { - lazy val msg: String = em"""An ${hl("implicit class")} may not be top-level""" + def msg = em"""An ${hl("implicit class")} may not be top-level""" - lazy val explanation: String = { + def explain = { val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef val exampleArgs = if(constr0.vparamss.isEmpty) "..." @@ -423,9 +423,9 @@ object messages { class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) extends SyntaxMsg(ImplicitCaseClassID) { - lazy val msg: String = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" + def msg = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" - lazy val explanation: String = + def explain = em"""|Implicit classes may not be case classes. Instead use a plain class: | |implicit class ${cdef.name}... @@ -435,8 +435,8 @@ object messages { class ImplicitClassPrimaryConstructorArity()(implicit ctx: Context) extends SyntaxMsg(ImplicitClassPrimaryConstructorArityID){ - lazy val msg: String = "Implicit classes must accept exactly one primary constructor parameter" - lazy val explanation: String = { + def msg = "Implicit classes must accept exactly one primary constructor parameter" + def explain = { val example = "implicit class RichDate(date: java.util.Date)" em"""Implicit classes may only take one non-implicit argument in their constructor. For example: | @@ -450,9 +450,9 @@ object messages { class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) extends SyntaxMsg(ObjectMayNotHaveSelfTypeID) { - lazy val msg: String = em"""${hl("object")}s must not have a self ${hl("type")}""" + def msg = em"""${hl("object")}s must not have a self ${hl("type")}""" - lazy val explanation: String = { + def explain = { val untpd.ModuleDef(name, tmpl) = mdef val ValDef(_, selfTpt, _) = tmpl.self em"""|${hl("object")}s must not have a self ${hl("type")}: @@ -467,9 +467,9 @@ object messages { class RepeatedModifier(modifier: String)(implicit ctx:Context) extends SyntaxMsg(RepeatedModifierID) { - lazy val msg: String = em"""Repeated modifier $modifier""" + def msg = em"""Repeated modifier $modifier""" - lazy val explanation: String = { + def explain = { val code1 = em"""private private val Origin = Point(0, 0)""" val code2 = em"""private final val Origin = Point(0, 0)""" em"""This happens when you accidentally specify the same modifier twice. @@ -488,8 +488,8 @@ object messages { class InterpolatedStringError()(implicit ctx:Context) extends SyntaxMsg(InterpolatedStringErrorID) { - lazy val msg: String = "Error in interpolated string: identifier or block expected" - lazy val explanation: String = { + def msg = "Error in interpolated string: identifier or block expected" + def explain = { val code1 = "s\"$new Point(0, 0)\"" val code2 = "s\"${new Point(0, 0)}\"" em"""|This usually happens when you forget to place your expressions inside curly braces. @@ -505,8 +505,8 @@ object messages { class UnboundPlaceholderParameter()(implicit ctx:Context) extends SyntaxMsg(UnboundPlaceholderParameterID) { - lazy val msg: String = em"""Unbound placeholder parameter; incorrect use of ${hl("_")}""" - lazy val explanation: String = + def msg = em"""Unbound placeholder parameter; incorrect use of ${hl("_")}""" + def explain = em"""|The ${hl("_")} placeholder syntax was used where it could not be bound. |Consider explicitly writing the variable binding. | @@ -540,16 +540,16 @@ object messages { class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) extends SyntaxMsg(IllegalStartSimpleExprID) { - lazy val msg: String = em"expression expected but ${Red(illegalToken)} found" - lazy val explanation: String = { + def msg = em"expression expected but ${Red(illegalToken)} found" + def explain = { em"""|An expression cannot start with ${Red(illegalToken)}.""" } } class MissingReturnType()(implicit ctx:Context) extends SyntaxMsg(MissingReturnTypeID) { - lazy val msg: String = "Missing return type" - lazy val explanation: String = + def msg = "Missing return type" + def explain = em"""|An abstract declaration must have a return type. For example: | |trait Shape {hl( @@ -559,8 +559,8 @@ object messages { class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) extends SyntaxMsg(MissingReturnTypeWithReturnStatementID) { - lazy val msg: String = em"$method has a return statement; it needs a result type" - lazy val explanation: String = + def msg = em"$method has a return statement; it needs a result type" + def explain = em"""|If a method contains a ${hl("return")} statement, it must have an |explicit return type. For example: | @@ -569,9 +569,9 @@ object messages { class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) extends SyntaxMsg(YieldOrDoExpectedInForComprehensionID) { - lazy val msg: String = em"${hl("yield")} or ${hl("do")} expected" + def msg = em"${hl("yield")} or ${hl("do")} expected" - lazy val explanation: String = + def explain = em"""|When the enumerators in a for comprehension are not placed in parentheses or |braces, a ${hl("do")} or ${hl("yield")} statement is required after the enumerators |section of the comprehension. @@ -601,10 +601,10 @@ object messages { class ProperDefinitionNotFound()(implicit ctx: Context) extends Message(ProperDefinitionNotFoundID) { - val kind: String = "Doc Comment" - lazy val msg: String = em"""Proper definition was not found in ${hl("@usecase")}""" + def kind: String = "Doc Comment" + def msg = em"""Proper definition was not found in ${hl("@usecase")}""" - lazy val explanation: String = { + def explain = { val noUsecase = "def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That" @@ -640,9 +640,9 @@ object messages { class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) extends SyntaxMsg(ByNameParameterNotSupportedID) { - lazy val msg: String = em"By-name parameter type ${tpe} not allowed here." + def msg = em"By-name parameter type ${tpe} not allowed here." - lazy val explanation: String = + def explain = em"""|By-name parameters act like functions that are only evaluated when referenced, |allowing for lazy evaluation of a parameter. | @@ -668,7 +668,7 @@ object messages { private val actualCount = actual.length private val msgPrefix = if (actualCount > expectedCount) "Too many" else "Not enough" - lazy val msg: String = + def msg = val expectedArgString = expectedArgs .map(_.paramName.unexpandedName.show) .mkString("[", ", ", "]") @@ -682,7 +682,7 @@ object messages { |expected: $expectedArgString |actual: $actualArgString""".stripMargin - lazy val explanation: String = { + def explain = { val tooManyTypeParams = """|val tuple2: (Int, String) = (1, "one") |val list: List[(Int, String)] = List(tuple2)""".stripMargin @@ -704,8 +704,8 @@ object messages { class IllegalVariableInPatternAlternative()(implicit ctx: Context) extends SyntaxMsg(IllegalVariableInPatternAlternativeID) { - lazy val msg: String = "Variables are not allowed in alternative patterns" - lazy val explanation: String = { + def msg = "Variables are not allowed in alternative patterns" + def explain = { val varInAlternative = """|def g(pair: (Int,Int)): Int = pair match { | case (1, n) | (n, 1) => n @@ -732,8 +732,8 @@ object messages { class IdentifierExpected(identifier: String)(implicit ctx: Context) extends SyntaxMsg(IdentifierExpectedID) { - lazy val msg: String = "identifier expected" - lazy val explanation: String = { + def msg = "identifier expected" + def explain = { val wrongIdentifier = em"def foo: $identifier = {...}" val validIdentifier = em"def foo = {...}" em"""|An identifier expected, but $identifier found. This could be because @@ -752,8 +752,8 @@ object messages { class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) extends SyntaxMsg(AuxConstructorNeedsNonImplicitParameterID) { - lazy val msg: String = "Auxiliary constructor needs non-implicit parameter list" - lazy val explanation: String = + def msg = "Auxiliary constructor needs non-implicit parameter list" + def explain = em"""|Only the primary constructor is allowed an ${hl("implicit")} parameter list; |auxiliary constructors need non-implicit parameter lists. When a primary |constructor has an implicit argslist, auxiliary constructors that call the @@ -767,8 +767,8 @@ object messages { class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) extends SyntaxMsg(IncorrectRepeatedParameterSyntaxID) { - lazy val msg: String = "'*' expected" - lazy val explanation: String = + def msg = "'*' expected" + def explain = em"""|Expected * in ${hl("_*")} operator. | |The ${hl("_*")} operator can be used to supply a sequence-based argument @@ -793,8 +793,8 @@ object messages { class IllegalLiteral()(implicit ctx: Context) extends SyntaxMsg(IllegalLiteralID) { - lazy val msg: String = "Illegal literal" - lazy val explanation: String = + def msg = "Illegal literal" + def explain = em"""|Available literals can be divided into several groups: | - Integer literals: 0, 21, 0xFFFFFFFF, -42L | - Floating Point Literals: 0.0, 1e30f, 3.14159f, 1.0e-100, .1 @@ -807,15 +807,15 @@ object messages { class PatternMatchExhaustivity(uncoveredFn: => String)(implicit ctx: Context) extends Message(PatternMatchExhaustivityID) { - val kind = "Pattern Match Exhaustivity" + def kind = "Pattern Match Exhaustivity" lazy val uncovered = uncoveredFn - lazy val msg: String = + def msg = em"""|${hl("match")} may not be exhaustive. | |It would fail on pattern case: $uncovered""" - lazy val explanation: String = + def explain = em"""|There are several ways to make the match exhaustive: | - Add missing cases as shown in the warning | - If an extractor always return ${hl("Some(...)")}, write ${hl("Some[X]")} for its return type @@ -825,8 +825,8 @@ object messages { class UncheckedTypePattern(msgFn: => String)(implicit ctx: Context) extends PatternMatchMsg(UncheckedTypePatternID) { - lazy val msg = msgFn - lazy val explanation: String = + def msg = msgFn + def explain = em"""|Type arguments and type refinements are erased during compile time, thus it's |impossible to check them at run-time. | @@ -836,21 +836,21 @@ object messages { class MatchCaseUnreachable()(implicit ctx: Context) extends Message(MatchCaseUnreachableID) { - val kind = "Match case Unreachable" - lazy val msg: String = "Unreachable case" - lazy val explanation: String = "" + def kind = "Match case Unreachable" + def msg = "Unreachable case" + def explain = "" } class MatchCaseOnlyNullWarning()(implicit ctx: Context) extends PatternMatchMsg(MatchCaseOnlyNullWarningID) { - lazy val msg: String = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" - lazy val explanation: String = "" + def msg = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" + def explain = "" } class SeqWildcardPatternPos()(implicit ctx: Context) extends SyntaxMsg(SeqWildcardPatternPosID) { - lazy val msg: String = em"""${hl("_*")} can be used only for last argument""" - lazy val explanation: String = { + def msg = em"""${hl("_*")} can be used only for last argument""" + def explain = { val code = """def sumOfTheFirstTwo(list: List[Int]): Int = list match { | case List(first, second, x:_*) => first + second @@ -872,8 +872,8 @@ object messages { class IllegalStartOfSimplePattern()(implicit ctx: Context) extends SyntaxMsg(IllegalStartOfSimplePatternID) { - lazy val msg: String = "pattern expected" - lazy val explanation: String = { + def msg = "pattern expected" + def explain = { val sipCode = """def f(x: Int, y: Int) = x match { | case `y` => ... @@ -951,16 +951,16 @@ object messages { class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) extends NamingMsg(PkgDuplicateSymbolID) { - lazy val msg: String = em"Trying to define package with same name as $existing" - lazy val explanation: String = "" + def msg = em"Trying to define package with same name as $existing" + def explain = "" } class ExistentialTypesNoLongerSupported()(implicit ctx: Context) extends SyntaxMsg(ExistentialTypesNoLongerSupportedID) { - lazy val msg: String = + def msg = em"""|Existential types are no longer supported - |use a wildcard or dependent type instead""" - lazy val explanation: String = + def explain = em"""|The use of existential types is no longer supported. | |You should use a wildcard or dependent type instead. @@ -979,8 +979,8 @@ object messages { class UnboundWildcardType()(implicit ctx: Context) extends SyntaxMsg(UnboundWildcardTypeID) { - lazy val msg: String = "Unbound wildcard type" - lazy val explanation: String = + def msg = "Unbound wildcard type" + def explain = em"""|The wildcard type syntax (${hl("_")}) was used where it could not be bound. |Replace ${hl("_")} with a non-wildcard type. If the type doesn't matter, |try replacing ${hl("_")} with ${hl("Any")}. @@ -1022,8 +1022,8 @@ object messages { } class DanglingThisInPath()(implicit ctx: Context) extends SyntaxMsg(DanglingThisInPathID) { - lazy val msg: String = em"""Expected an additional member selection after the keyword ${hl("this")}""" - lazy val explanation: String = + def msg = em"""Expected an additional member selection after the keyword ${hl("this")}""" + def explain = val contextCode: String = """ trait Outer { | val member: Int @@ -1054,9 +1054,9 @@ object messages { class OverridesNothing(member: Symbol)(implicit ctx: Context) extends DeclarationMsg(OverridesNothingID) { - lazy val msg: String = em"""${member} overrides nothing""" + def msg = em"""${member} overrides nothing""" - lazy val explanation: String = + def explain = em"""|There must be a field or method with the name ${member.name} in a super |class of ${member.owner} to override it. Did you misspell it? |Are you extending the right classes? @@ -1065,8 +1065,8 @@ object messages { class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) extends DeclarationMsg(OverridesNothingButNameExistsID) { - lazy val msg: String = em"""${member} has a different signature than the overridden declaration""" - lazy val explanation: String = + def msg = em"""${member} has a different signature than the overridden declaration""" + def explain = val existingDecl: String = existing.map(_.showDcl).mkString(" \n") em"""|There must be a non-final field or method with the name ${member.name} and the |same parameter list in a super class of ${member.owner} to override it. @@ -1081,9 +1081,9 @@ object messages { class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) extends ReferenceMsg(ForwardReferenceExtendsOverDefinitionID) { - lazy val msg: String = em"${definition.name} is a forward reference extending over the definition of ${value.name}" + def msg = em"${definition.name} is a forward reference extending over the definition of ${value.name}" - lazy val explanation: String = + def explain = em"""|${definition.name} is used before you define it, and the definition of ${value.name} |appears between that use and the definition of ${definition.name}. | @@ -1102,13 +1102,13 @@ object messages { private lazy val foundText = Tokens.showToken(found) - lazy val msg: String = + def msg = val expectedText = if (Tokens.isIdentifier(expected)) "an identifier" else Tokens.showToken(expected) em"""${expectedText} expected, but ${foundText} found""" - lazy val explanation: String = + def explain = if (Tokens.isIdentifier(expected) && Tokens.isKeyword(found)) s""" |If you want to use $foundText as identifier, you may put it in backticks: `$foundText`.""".stripMargin @@ -1118,11 +1118,11 @@ object messages { class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) extends SyntaxMsg(MixedLeftAndRightAssociativeOpsID) { - lazy val msg: String = + def msg = val op1Asso: String = if (op2LeftAssoc) "which is right-associative" else "which is left-associative" val op2Asso: String = if (op2LeftAssoc) "which is left-associative" else "which is right-associative" em"${op1} (${op1Asso}) and ${op2} ($op2Asso) have same precedence and may not be mixed" - lazy val explanation: String = + def explain = s"""|The operators ${op1} and ${op2} are used as infix operators in the same expression, |but they bind to different sides: |${op1} is applied to the operand to its ${if (op2LeftAssoc) "right" else "left"} @@ -1153,8 +1153,8 @@ object messages { class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) extends TypeMsg(CantInstantiateAbstractClassOrTraitID) { private val traitOrAbstract = if (isTrait) "a trait" else "abstract" - lazy val msg: String = em"""${cls.name} is ${traitOrAbstract}; it cannot be instantiated""" - lazy val explanation: String = + def msg = em"""${cls.name} is ${traitOrAbstract}; it cannot be instantiated""" + def explain = em"""|Abstract classes and traits need to be extended by a concrete class or object |to make their functionality accessible. | @@ -1169,16 +1169,16 @@ object messages { } class UnreducibleApplication(tycon: Type)(using Context) extends TypeMsg(UnreducibleApplicationID): - lazy val msg = em"unreducible application of higher-kinded type $tycon to wildcard arguments" - lazy val explanation = + def msg = em"unreducible application of higher-kinded type $tycon to wildcard arguments" + def explain = em"""|An abstract type constructor cannot be applied to wildcard arguments. |Such applications are equivalent to existential types, which are not |supported in Scala 3.""" class OverloadedOrRecursiveMethodNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) extends CyclicMsg(OverloadedOrRecursiveMethodNeedsResultTypeID) { - lazy val msg: String = em"""Overloaded or recursive $cycleSym needs return type""" - lazy val explanation: String = + def msg = em"""Overloaded or recursive $cycleSym needs return type""" + def explain = em"""Case 1: $cycleSym is overloaded |If there are multiple methods named $cycleSym and at least one definition of |it calls another, you need to specify the calling method's return type. @@ -1191,18 +1191,18 @@ object messages { class RecursiveValueNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) extends CyclicMsg(RecursiveValueNeedsResultTypeID) { - lazy val msg: String = em"""Recursive $cycleSym needs type""" - lazy val explanation: String = + def msg = em"""Recursive $cycleSym needs type""" + def explain = em"""The definition of $cycleSym is recursive and you need to specify its type. |""".stripMargin } class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) extends CyclicMsg(CyclicReferenceInvolvingID) { - lazy val msg: String = + def msg = val where = if denot.exists then s" involving $denot" else "" em"Cyclic reference$where" - lazy val explanation: String = + def explain = em"""|$denot is declared as part of a cycle which makes it impossible for the |compiler to decide upon ${denot.name}'s type. |To avoid this error, try giving ${denot.name} an explicit type. @@ -1211,8 +1211,8 @@ object messages { class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) extends CyclicMsg(CyclicReferenceInvolvingImplicitID) { - lazy val msg: String = em"""Cyclic reference involving implicit $cycleSym""" - lazy val explanation: String = + def msg = em"""Cyclic reference involving implicit $cycleSym""" + def explain = em"""|$cycleSym is declared as part of a cycle which makes it impossible for the |compiler to decide upon ${cycleSym.name}'s type. |This might happen when the right hand-side of $cycleSym's definition involves an implicit search. @@ -1222,8 +1222,8 @@ object messages { class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(implicit ctx: Context) extends ReferenceMsg(SuperQualMustBeParentID) { - lazy val msg: String = em"""|$qual does not name a parent of $cls""" - lazy val explanation: String = + def msg = em"""|$qual does not name a parent of $cls""" + def explain = val parents: Seq[String] = (cls.info.parents map (_.typeSymbol.name.show)).sorted em"""|When a qualifier ${hl("T")} is used in a ${hl("super")} prefix of the form ${hl("C.super[T]")}, |${hl("T")} must be a parent type of ${hl("C")}. @@ -1235,8 +1235,8 @@ object messages { class VarArgsParamMustComeLast()(implicit ctx: Context) extends SyntaxMsg(IncorrectRepeatedParameterSyntaxID) { - lazy val msg: String = em"""${hl("varargs")} parameter must come last""" - lazy val explanation: String = + def msg = em"""${hl("varargs")} parameter must come last""" + def explain = em"""|The ${hl("varargs")} field must be the last field in the method signature. |Attempting to define a field in a method signature after a ${hl("varargs")} field is an error. |""" @@ -1265,12 +1265,12 @@ object messages { ex"""$howVisible$qualifier in ${em"${whereFound.owner}"}""" } - lazy val msg: String = + def msg = i"""|Reference to ${em"$name"} is ambiguous |it is both ${bindingString(newPrec, ctx)} |and ${bindingString(prevPrec, prevCtx, " subsequently")}""" - lazy val explanation: String = + def explain = em"""|The compiler can't decide which of the possible choices you |are referencing with $name. |Note: @@ -1285,14 +1285,14 @@ object messages { extends TypeMsg(MethodDoesNotTakeParametersId) { def methodSymbol: Symbol = tpd.methPart(tree).symbol - lazy val msg: String = { + def msg = { val more = if (tree.isInstanceOf[tpd.Apply]) " more" else "" val meth = methodSymbol val methStr = if (meth.exists) methodSymbol.showLocated else "expression" em"$methStr does not take$more parameters" } - lazy val explanation: String = { + def explain = { val isNullary = methodSymbol.info.isInstanceOf[ExprType] val addendum = if (isNullary) "\nNullary methods may not be called with parenthesis" @@ -1308,10 +1308,10 @@ object messages { implicit ctx: Context) extends ReferenceMsg(AmbiguousOverloadID) { private def all = if (alternatives.length == 2) "both" else "all" - lazy val msg: String = + def msg = s"""|Ambiguous overload. The ${err.overloadedAltsStr(alternatives)} |$all match ${err.expectedTypeStr(pt)}""".stripMargin - lazy val explanation: String = + def explain = em"""|There are ${alternatives.length} methods that could be referenced as the compiler knows too little |about the expected type. |You may specify the expected type e.g. by @@ -1322,8 +1322,8 @@ object messages { class ReassignmentToVal(name: Name)(implicit ctx: Context) extends TypeMsg(ReassignmentToValID) { - lazy val msg: String = em"""Reassignment to val $name""" - lazy val explanation: String = + def msg = em"""Reassignment to val $name""" + def explain = em"""|You can not assign a new value to $name as values can't be changed. |Keep in mind that every statement has a value, so you may e.g. use | ${hl("val")} $name ${hl("= if (condition) 2 else 5")} @@ -1335,8 +1335,8 @@ object messages { class TypeDoesNotTakeParameters(tpe: Type, params: List[Trees.Tree[Trees.Untyped]])(implicit ctx: Context) extends TypeMsg(TypeDoesNotTakeParametersID) { - lazy val msg: String = em"$tpe does not take type parameters" - lazy val explanation: String = + def msg = em"$tpe does not take type parameters" + def explain = val ps = if (params.size == 1) s"a type parameter ${params.head}" else s"type parameters ${params.map(_.show).mkString(", ")}" @@ -1347,8 +1347,8 @@ object messages { class ParameterizedTypeLacksArguments(psym: Symbol)(implicit ctx: Context) extends TypeMsg(ParameterizedTypeLacksArgumentsID) { - lazy val msg: String = em"Parameterized $psym lacks argument list" - lazy val explanation: String = + def msg = em"Parameterized $psym lacks argument list" + def explain = em"""The $psym is declared with non-implicit parameters, you may not leave |out the parameter list when extending it. |""" @@ -1357,8 +1357,8 @@ object messages { class VarValParametersMayNotBeCallByName(name: TermName, mutable: Boolean)(implicit ctx: Context) extends SyntaxMsg(VarValParametersMayNotBeCallByNameID) { def varOrVal = if (mutable) em"${hl("var")}" else em"${hl("val")}" - lazy val msg: String = s"$varOrVal parameters may not be call-by-name" - lazy val explanation: String = + def msg = s"$varOrVal parameters may not be call-by-name" + def explain = em"""${hl("var")} and ${hl("val")} parameters of classes and traits may no be call-by-name. In case you |want the parameter to be evaluated on demand, consider making it just a parameter |and a ${hl("def")} in the class such as @@ -1370,34 +1370,34 @@ object messages { class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) extends SyntaxMsg(MissingTypeParameterForID) { - lazy val msg: String = + def msg = if (tpe.derivesFrom(defn.AnyKindClass)) em"${tpe} cannot be used as a value type" else em"Missing type parameter for ${tpe}" - lazy val explanation: String = "" + def explain = "" } class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) extends TypeMsg(MissingTypeParameterInTypeAppID) { def numParams = tpe.typeParams.length def parameters = if (numParams == 1) "parameter" else "parameters" - lazy val msg: String = em"Missing type $parameters for $tpe" - lazy val explanation: String = em"A fully applied type is expected but $tpe takes $numParams $parameters" + def msg = em"Missing type $parameters for $tpe" + def explain = em"A fully applied type is expected but $tpe takes $numParams $parameters" } class DoesNotConformToBound(tpe: Type, which: String, bound: Type)( err: Errors)(implicit ctx: Context) extends TypeMismatchMsg(DoesNotConformToBoundID) { - lazy val msg: String = em"Type argument ${tpe} does not conform to $which bound $bound${err.whyNoMatchStr(tpe, bound)}" - lazy val explanation: String = "" + def msg = em"Type argument ${tpe} does not conform to $which bound $bound${err.whyNoMatchStr(tpe, bound)}" + def explain = "" } class DoesNotConformToSelfType(category: String, selfType: Type, cls: Symbol, otherSelf: Type, relation: String, other: Symbol)( implicit ctx: Context) extends TypeMismatchMsg(DoesNotConformToSelfTypeID) { - lazy val msg: String = em"""$category: self type $selfType of $cls does not conform to self type $otherSelf + def msg = em"""$category: self type $selfType of $cls does not conform to self type $otherSelf |of $relation $other""" - lazy val explanation: String = + def explain = em"""You mixed in $other which requires self type $otherSelf, but $cls has self type |$selfType and does not inherit from $otherSelf. | @@ -1409,8 +1409,8 @@ object messages { class DoesNotConformToSelfTypeCantBeInstantiated(tp: Type, selfType: Type)( implicit ctx: Context) extends TypeMismatchMsg(DoesNotConformToSelfTypeCantBeInstantiatedID) { - lazy val msg: String = em"""$tp does not conform to its self type $selfType; cannot be instantiated""" - lazy val explanation: String = + def msg = em"""$tp does not conform to its self type $selfType; cannot be instantiated""" + def explain = em"""To create an instance of $tp it needs to inherit $selfType in some way. | |Note: Self types are indicated with the notation @@ -1421,50 +1421,50 @@ object messages { class AbstractMemberMayNotHaveModifier(sym: Symbol, flag: FlagSet)( implicit ctx: Context) extends SyntaxMsg(AbstractMemberMayNotHaveModifierID) { - lazy val msg: String = em"""${hl("abstract")} $sym may not have `${flag.flagsString}` modifier""" - lazy val explanation: String = "" + def msg = em"""${hl("abstract")} $sym may not have `${flag.flagsString}` modifier""" + def explain = "" } class TopLevelCantBeImplicit(sym: Symbol)( implicit ctx: Context) extends SyntaxMsg(TopLevelCantBeImplicitID) { - lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for top-level definitions""" - lazy val explanation: String = "" + def msg = em"""${hl("implicit")} modifier cannot be used for top-level definitions""" + def explain = "" } class TypesAndTraitsCantBeImplicit()(implicit ctx: Context) extends SyntaxMsg(TypesAndTraitsCantBeImplicitID) { - lazy val msg: String = em"""${hl("implicit")} modifier cannot be used for types or traits""" - lazy val explanation: String = "" + def msg = em"""${hl("implicit")} modifier cannot be used for types or traits""" + def explain = "" } class OnlyClassesCanBeAbstract(sym: Symbol)( implicit ctx: Context) extends SyntaxMsg(OnlyClassesCanBeAbstractID) { - lazy val explanation: String = "" - lazy val msg: String = em"""${hl("abstract")} modifier can be used only for classes; it should be omitted for abstract members""" + def explain = "" + def msg = em"""${hl("abstract")} modifier can be used only for classes; it should be omitted for abstract members""" } class AbstractOverrideOnlyInTraits(sym: Symbol)( implicit ctx: Context) extends SyntaxMsg(AbstractOverrideOnlyInTraitsID) { - lazy val msg: String = em"""${hl("abstract override")} modifier only allowed for members of traits""" - lazy val explanation: String = "" + def msg = em"""${hl("abstract override")} modifier only allowed for members of traits""" + def explain = "" } class TraitsMayNotBeFinal(sym: Symbol)( implicit ctx: Context) extends SyntaxMsg(TraitsMayNotBeFinalID) { - lazy val msg: String = em"""$sym may not be ${hl("final")}""" - lazy val explanation: String = + def msg = em"""$sym may not be ${hl("final")}""" + def explain = "A trait can never be final since it is abstract and must be extended to be useful." } class NativeMembersMayNotHaveImplementation(sym: Symbol)( implicit ctx: Context) extends SyntaxMsg(NativeMembersMayNotHaveImplementationID) { - lazy val msg: String = em"""${hl("@native")} members may not have an implementation""" - lazy val explanation: String = "" + def msg = em"""${hl("@native")} members may not have an implementation""" + def explain = "" } class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( @@ -1474,14 +1474,14 @@ object messages { private def varNote = if (sym.is(Mutable)) "Note that variables need to be initialized to be defined." else "" - lazy val msg: String = em"""Declaration of $sym not allowed here: only classes can have declared but undefined members""" - lazy val explanation: String = s"$varNote" + def msg = em"""Declaration of $sym not allowed here: only classes can have declared but undefined members""" + def explain = s"$varNote" } class CannotExtendAnyVal(sym: Symbol)(implicit ctx: Context) extends SyntaxMsg(CannotExtendAnyValID) { - lazy val msg: String = em"""$sym cannot extend ${hl("AnyVal")}""" - lazy val explanation: String = + def msg = em"""$sym cannot extend ${hl("AnyVal")}""" + def explain = em"""Only classes (not traits) are allowed to extend ${hl("AnyVal")}, but traits may extend |${hl("Any")} to become ${Green("\"universal traits\"")} which may only have ${hl("def")} members. |Universal traits can be mixed into classes that extend ${hl("AnyVal")}. @@ -1499,8 +1499,8 @@ object messages { |""".stripMargin } - lazy val msg: String = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage - lazy val explanation: String = "" + def msg = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage + def explain = "" } object CannotHaveSameNameAs { sealed trait Reason @@ -1510,87 +1510,87 @@ object messages { class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotDefineInnerID) { - lazy val msg: String = em"""Value classes may not define an inner class""" - lazy val explanation: String = "" + def msg = em"""Value classes may not define an inner class""" + def explain = "" } class ValueClassesMayNotDefineNonParameterField(valueClass: Symbol, field: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotDefineNonParameterFieldID) { - lazy val msg: String = em"""Value classes may not define non-parameter field""" - lazy val explanation: String = "" + def msg = em"""Value classes may not define non-parameter field""" + def explain = "" } class ValueClassesMayNotDefineASecondaryConstructor(valueClass: Symbol, constructor: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotDefineASecondaryConstructorID) { - lazy val msg: String = em"""Value classes may not define a secondary constructor""" - lazy val explanation: String = "" + def msg = em"""Value classes may not define a secondary constructor""" + def explain = "" } class ValueClassesMayNotContainInitalization(valueClass: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotContainInitalizationID) { - lazy val msg: String = em"""Value classes may not contain initialization statements""" - lazy val explanation: String = "" + def msg = em"""Value classes may not contain initialization statements""" + def explain = "" } class ValueClassesMayNotBeAbstract(valueClass: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotBeAbstractID) { - lazy val msg: String = em"""Value classes may not be ${hl("abstract")}""" - lazy val explanation: String = "" + def msg = em"""Value classes may not be ${hl("abstract")}""" + def explain = "" } class ValueClassesMayNotBeContainted(valueClass: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotBeContaintedID) { private def localOrMember = if (valueClass.owner.isTerm) "local class" else "member of another class" - lazy val msg: String = s"""Value classes may not be a $localOrMember""" - lazy val explanation: String = "" + def msg = s"""Value classes may not be a $localOrMember""" + def explain = "" } class ValueClassesMayNotWrapItself(valueClass: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassesMayNotWrapItselfID) { - lazy val msg: String = """A value class may not wrap itself""" - lazy val explanation: String = "" + def msg = """A value class may not wrap itself""" + def explain = "" } class ValueClassParameterMayNotBeAVar(valueClass: Symbol, param: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassParameterMayNotBeAVarID) { - lazy val msg: String = em"""A value class parameter may not be a ${hl("var")}""" - lazy val explanation: String = + def msg = em"""A value class parameter may not be a ${hl("var")}""" + def explain = em"""A value class must have exactly one ${hl("val")} parameter.""" } class ValueClassNeedsOneValParam(valueClass: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassNeedsExactlyOneValParamID) { - lazy val msg: String = em"""Value class needs one ${hl("val")} parameter""" - lazy val explanation: String = "" + def msg = em"""Value class needs one ${hl("val")} parameter""" + def explain = "" } class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(implicit ctx: Context) extends SyntaxMsg(ValueClassParameterMayNotBeCallByNameID) { - lazy val msg: String = s"Value class parameter `${param.name}` may not be call-by-name" - lazy val explanation: String = "" + def msg = s"Value class parameter `${param.name}` may not be call-by-name" + def explain = "" } class OnlyCaseClassOrCaseObjectAllowed()(implicit ctx: Context) extends SyntaxMsg(OnlyCaseClassOrCaseObjectAllowedID) { - lazy val msg: String = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" - lazy val explanation: String = "" + def msg = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" + def explain = "" } class ExpectedToplevelDef()(implicit ctx: Context) extends SyntaxMsg(ExpectedTopLevelDefID) { - lazy val msg: String = "Expected a toplevel definition" - lazy val explanation: String = "" + def msg = "Expected a toplevel definition" + def explain = "" } class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context) extends SyntaxMsg(SuperCallsNotAllowedInlineableID) { - lazy val msg: String = em"Super call not allowed in inlineable $symbol" - lazy val explanation: String = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." + def msg = em"Super call not allowed in inlineable $symbol" + def explain = "Method inlining prohibits calling superclass methods, as it may lead to confusion about which super is being called." } class NotAPath(tp: Type, usage: String)(using Context) extends TypeMsg(NotAPathID): - lazy val msg: String = em"$tp is not a valid $usage, since it is not an immutable path" - lazy val explanation: String = + def msg = em"$tp is not a valid $usage, since it is not an immutable path" + def explain = i"""An immutable path is | - a reference to an immutable value, or | - a reference to `this`, or @@ -1598,28 +1598,28 @@ object messages { class WrongNumberOfParameters(expected: Int)(implicit ctx: Context) extends SyntaxMsg(WrongNumberOfParametersID) { - lazy val msg: String = s"Wrong number of parameters, expected: $expected" - lazy val explanation: String = "" + def msg = s"Wrong number of parameters, expected: $expected" + def explain = "" } class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) extends SyntaxMsg(DuplicatePrivateProtectedQualifierID) { - lazy val msg: String = "Duplicate private/protected qualifier" - lazy val explanation: String = + def msg = "Duplicate private/protected qualifier" + def explain = em"It is not allowed to combine `private` and `protected` modifiers even if they are qualified to different scopes" } class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) extends SyntaxMsg(ExpectedStartOfTopLevelDefinitionID) { - lazy val msg: String = "Expected start of definition" - lazy val explanation: String = + def msg = "Expected start of definition" + def explain = em"You have to provide either ${hl("class")}, ${hl("trait")}, ${hl("object")}, or ${hl("enum")} definitions after qualifiers" } class NoReturnFromInlineable(owner: Symbol)(implicit ctx: Context) extends SyntaxMsg(NoReturnFromInlineableID) { - lazy val msg: String = em"No explicit ${hl("return")} allowed from inlineable $owner" - lazy val explanation: String = + def msg = em"No explicit ${hl("return")} allowed from inlineable $owner" + def explain = em"""Methods marked with ${hl("inline")} modifier may not use ${hl("return")} statements. |Instead, you should rely on the last expression's value being |returned from a method. @@ -1628,8 +1628,8 @@ object messages { class ReturnOutsideMethodDefinition(owner: Symbol)(implicit ctx: Context) extends SyntaxMsg(ReturnOutsideMethodDefinitionID) { - lazy val msg: String = em"${hl("return")} outside method definition" - lazy val explanation: String = + def msg = em"${hl("return")} outside method definition" + def explain = em"""You used ${hl("return")} in ${owner}. |${hl("return")} is a keyword and may only be used within method declarations. |""" @@ -1637,16 +1637,16 @@ object messages { class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) extends SyntaxMsg(ExtendFinalClassID) { - lazy val msg: String = em"$clazz cannot extend ${hl("final")} $finalClazz" - lazy val explanation: String = + def msg = em"$clazz cannot extend ${hl("final")} $finalClazz" + def explain = em"""A class marked with the ${hl("final")} keyword cannot be extended""" } class ExpectedTypeBoundOrEquals(found: Token)(implicit ctx: Context) extends SyntaxMsg(ExpectedTypeBoundOrEqualsID) { - lazy val msg: String = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" + def msg = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" - lazy val explanation: String = + def explain = em"""Type parameters and abstract types may be constrained by a type bound. |Such type bounds limit the concrete values of the type variables and possibly |reveal more information about the members of such types. @@ -1661,8 +1661,8 @@ object messages { class ClassAndCompanionNameClash(cls: Symbol, other: Symbol)(implicit ctx: Context) extends NamingMsg(ClassAndCompanionNameClashID) { - lazy val msg: String = em"Name clash: both ${cls.owner} and its companion object defines ${cls.name.stripModuleClassSuffix}" - lazy val explanation: String = + def msg = em"Name clash: both ${cls.owner} and its companion object defines ${cls.name.stripModuleClassSuffix}" + def explain = em"""|A ${cls.kindString} and its companion object cannot both define a ${hl("class")}, ${hl("trait")} or ${hl("object")} with the same name: | - ${cls.owner} defines ${cls} | - ${other.owner} defines ${other}""" @@ -1670,7 +1670,7 @@ object messages { class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) extends SyntaxMsg(TailrecNotApplicableID) { - lazy val msg: String = { + def msg = { val reason = if (!symbol.is(Method)) em"$symbol isn't a method" else if (symbol.is(Deferred)) em"$symbol is abstract" @@ -1679,13 +1679,13 @@ object messages { s"TailRec optimisation not applicable, $reason" } - lazy val explanation: String = "" + def explain = "" } class FailureToEliminateExistential(tp: Type, tp1: Type, tp2: Type, boundSyms: List[Symbol])(implicit ctx: Context) extends Message(FailureToEliminateExistentialID) { - val kind: String = "Compatibility" - lazy val msg: String = + def kind: String = "Compatibility" + def msg = val originalType = ctx.printer.dclsText(boundSyms, "; ").show em"""An existential type that came from a Scala-2 classfile cannot be |mapped accurately to to a Scala-3 equivalent. @@ -1694,7 +1694,7 @@ object messages { |type used instead: $tp2 |This choice can cause follow-on type errors or hide type errors. |Proceed at own risk.""" - lazy val explanation: String = + def explain = em"""Existential types in their full generality are no longer supported. |Scala-3 does applications of class types to wildcard type arguments. |Other forms of existential types that come from Scala-2 classfiles @@ -1703,16 +1703,16 @@ object messages { class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(implicit ctx: Context) extends SyntaxMsg(OnlyFunctionsCanBeFollowedByUnderscoreID) { - lazy val msg: String = em"Only function types can be followed by ${hl("_")} but the current expression has type $tp" - lazy val explanation: String = + def msg = em"Only function types can be followed by ${hl("_")} but the current expression has type $tp" + def explain = em"""The syntax ${hl("x _")} is no longer supported if ${hl("x")} is not a function. |To convert to a function value, you need to explicitly write ${hl("() => x")}""" } class MissingEmptyArgumentList(method: Symbol)(implicit ctx: Context) extends SyntaxMsg(MissingEmptyArgumentListID) { - lazy val msg: String = em"$method must be called with ${hl("()")} argument" - lazy val explanation: String = { + def msg = em"$method must be called with ${hl("()")} argument" + def explain = { val codeExample = """def next(): T = ... |next // is expanded to next()""" @@ -1728,27 +1728,27 @@ object messages { class DuplicateNamedTypeParameter(name: Name)(implicit ctx: Context) extends SyntaxMsg(DuplicateNamedTypeParameterID) { - lazy val msg: String = em"Type parameter $name was defined multiple times." - lazy val explanation: String = "" + def msg = em"Type parameter $name was defined multiple times." + def explain = "" } class UndefinedNamedTypeParameter(undefinedName: Name, definedNames: List[Name])(implicit ctx: Context) extends SyntaxMsg(UndefinedNamedTypeParameterID) { - lazy val msg: String = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." - lazy val explanation: String = "" + def msg = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." + def explain = "" } class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends SyntaxMsg(IllegalStartOfStatementID) { - lazy val msg: String = { + def msg = { val addendum = if (isModifier) ": no modifiers allowed here" else "" "Illegal start of statement" + addendum } - lazy val explanation: String = "A statement is either an import, a definition or an expression." + def explain = "A statement is either an import, a definition or an expression." } class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends SyntaxMsg(TraitIsExpectedID) { - lazy val msg: String = em"$symbol is not a trait" - lazy val explanation: String = { + def msg = em"$symbol is not a trait" + def explain = { val errorCodeExample = """class A |class B @@ -1774,25 +1774,25 @@ object messages { } class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends SyntaxMsg(TraitRedefinedFinalMethodFromAnyRefID) { - lazy val msg: String = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." - lazy val explanation: String = "" + def msg = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." + def explain = "" } class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends NamingMsg(PackageNameAlreadyDefinedID) { lazy val (where, or) = if pkg.associatedFile == null then ("", "") else (s" in ${pkg.associatedFile}", " or delete the containing class file") - lazy val msg: String = em"""${pkg.name} is the name of $pkg$where. + def msg = em"""${pkg.name} is the name of $pkg$where. |It cannot be used at the same time as the name of a package.""" - lazy val explanation: String = + def explain = em"""An ${hl("object")} or other toplevel definition cannot have the same name as an existing ${hl("package")}. |Rename either one of them$or.""" } class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) extends SyntaxMsg(UnapplyInvalidNumberOfArgumentsID) { - lazy val msg: String = em"Wrong number of argument patterns for $qual; expected: ($argTypes%, %)" - lazy val explanation: String = + def msg = em"Wrong number of argument patterns for $qual; expected: ($argTypes%, %)" + def explain = em"""The Unapply method of $qual was used with incorrect number of arguments. |Expected usage would be something like: |case $qual(${argTypes.map(_ => '_')}%, %) => ... @@ -1803,13 +1803,13 @@ object messages { class UnapplyInvalidReturnType(unapplyResult: Type, unapplyName: Symbol#ThisName)(implicit ctx: Context) extends DeclarationMsg(UnapplyInvalidReturnTypeID) { - lazy val msg = + def msg = val addendum = if (ctx.scala2CompatMode && unapplyName == nme.unapplySeq) "\nYou might want to try to rewrite the extractor to use `unapply` instead." else "" em"""| ${Red(i"$unapplyResult")} is not a valid result type of an $unapplyName method of an ${Magenta("extractor")}.$addendum""" - lazy val explanation = if (unapplyName.show == "unapply") + def explain = if (unapplyName.show == "unapply") em""" |To be used as an extractor, an unapply method has to return a type that either: | - has members ${Magenta("isEmpty: Boolean")} and ${Magenta("get: S")} (usually an ${Green("Option[S]")}) @@ -1857,14 +1857,14 @@ object messages { } class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends SyntaxMsg(StaticFieldsOnlyAllowedInObjectsID) { - lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}." - lazy val explanation: String = + def msg = em"${hl("@static")} $member in ${member.owner} must be defined inside an ${hl("object")}." + def explain = em"${hl("@static")} members are only allowed inside objects." } class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends SyntaxMsg(StaticFieldsShouldPrecedeNonStaticID) { - lazy val msg: String = em"${hl("@static")} $member in ${member.owner} must be defined before non-static fields." - lazy val explanation: String = { + def msg = em"${hl("@static")} $member in ${member.owner} must be defined before non-static fields." + def explain = { val nonStatics = defns.takeWhile(_.symbol != member).take(3).filter(_.isInstanceOf[tpd.ValDef]) val codeExample = s"""object ${member.owner.name.firstPart} { | @static ${member} = ... @@ -1883,8 +1883,8 @@ object messages { } class CyclicInheritance(symbol: Symbol, addendum: => String)(implicit ctx: Context) extends SyntaxMsg(CyclicInheritanceID) { - lazy val msg: String = em"Cyclic inheritance: $symbol extends itself$addendum" - lazy val explanation: String = { + def msg = em"Cyclic inheritance: $symbol extends itself$addendum" + def explain = { val codeExample = "class A extends A" em"""Cyclic inheritance is prohibited in Dotty. @@ -1900,7 +1900,7 @@ object messages { class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) extends ReferenceMsg(BadSymbolicReferenceID) { - lazy val msg: String = { + def msg = { val denotationOwner = denot.owner val denotationName = ctx.fresh.setSetting(ctx.settings.YdebugNames, true).printer.nameString(denot.name) val file = denot.symbol.associatedFile @@ -1914,18 +1914,18 @@ object messages { |the classpath might be incompatible with the version used when compiling $src.""" } - lazy val explanation: String = "" + def explain = "" } class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends SyntaxMsg(UnableToExtendSealedClassID) { - lazy val msg: String = em"Cannot extend ${hl("sealed")} $pclazz in a different source file" - lazy val explanation: String = "A sealed class or trait can only be extended in the same file as its declaration" + def msg = em"Cannot extend ${hl("sealed")} $pclazz in a different source file" + def explain = "A sealed class or trait can only be extended in the same file as its declaration" } class SymbolHasUnparsableVersionNumber(symbol: Symbol, migrationMessage: => String)(implicit ctx: Context) extends SyntaxMsg(SymbolHasUnparsableVersionNumberID) { - lazy val msg: String = em"${symbol.showLocated} has an unparsable version number: $migrationMessage" - lazy val explanation: String = + def msg = em"${symbol.showLocated} has an unparsable version number: $migrationMessage" + def explain = em"""$migrationMessage | |The ${symbol.showLocated} is marked with ${hl("@migration")} indicating it has changed semantics @@ -1937,8 +1937,8 @@ object messages { symbol: Symbol, migrationVersion: ScalaVersion )(implicit ctx: Context) extends SyntaxMsg(SymbolChangedSemanticsInVersionID) { - lazy val msg: String = em"${symbol.showLocated} has changed semantics in version $migrationVersion" - lazy val explanation: String = { + def msg = em"${symbol.showLocated} has changed semantics in version $migrationVersion" + def explain = { em"""The ${symbol.showLocated} is marked with ${hl("@migration")} indicating it has changed semantics |between versions and the ${hl("-Xmigration")} settings is used to warn about constructs |whose behavior may have changed since version change.""" @@ -1948,8 +1948,8 @@ object messages { class UnableToEmitSwitch(tooFewCases: Boolean)(implicit ctx: Context) extends SyntaxMsg(UnableToEmitSwitchID) { def tooFewStr: String = if (tooFewCases) " since there are not enough cases" else "" - lazy val msg: String = em"Could not emit switch for ${hl("@switch")} annotated match$tooFewStr" - lazy val explanation: String = { + def msg = em"Could not emit switch for ${hl("@switch")} annotated match$tooFewStr" + def explain = { val codeExample = """val ConstantB = 'B' |final val ConstantC = 'C' @@ -1976,15 +1976,15 @@ object messages { class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) extends SyntaxMsg(MissingCompanionForStaticID) { - lazy val msg: String = em"${member.owner} does not have a companion class" - lazy val explanation: String = + def msg = em"${member.owner} does not have a companion class" + def explain = em"An object that contains ${hl("@static")} members must have a companion class." } class PolymorphicMethodMissingTypeInParent(rsym: Symbol, parentSym: Symbol)(implicit ctx: Context) extends SyntaxMsg(PolymorphicMethodMissingTypeInParentID) { - lazy val msg: String = em"Polymorphic refinement $rsym without matching type in parent $parentSym is no longer allowed" - lazy val explanation: String = + def msg = em"Polymorphic refinement $rsym without matching type in parent $parentSym is no longer allowed" + def explain = em"""Polymorphic $rsym is not allowed in the structural refinement of $parentSym because |$rsym does not override any method in $parentSym. Structural refinement does not allow for |polymorphic methods.""" @@ -1992,23 +1992,23 @@ object messages { class ParamsNoInline(owner: Symbol)(implicit ctx: Context) extends SyntaxMsg(ParamsNoInlineID) { - lazy val msg: String = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" - lazy val explanation: String = "" + def msg = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" + def explain = "" } class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends TypeMsg(JavaSymbolIsNotAValueID) { - lazy val msg: String = { + def msg = { val kind = if (symbol is Package) em"$symbol" else em"Java defined ${hl("class " + symbol.name)}" s"$kind is not a value" } - lazy val explanation: String = "" + def explain = "" } class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends NamingMsg(DoubleDefinitionID) { - lazy val msg: String = { + def msg = { def nameAnd = if (decl.name != previousDecl.name) " name and" else "" def details(implicit ctx: Context): String = if (decl.isRealMethod && previousDecl.isRealMethod) { @@ -2049,42 +2049,42 @@ object messages { |${decl.showDcl} ${symLocation(decl)} |""" + details } - lazy val explanation: String = "" + def explain = "" } class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends SyntaxMsg(ImportRenamedTwiceID) { - lazy val msg: String = s"${ident.show} is renamed twice on the same import line." - lazy val explanation: String = "" + def msg = s"${ident.show} is renamed twice on the same import line." + def explain = "" } class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends SyntaxMsg(TypeTestAlwaysSucceedsID) { - lazy val msg: String = { + def msg = { val addendum = if (foundCls != testCls) s" is a subtype of $testCls" else " is the same as the tested type" s"The highlighted type test will always succeed since the scrutinee type ($foundCls)" + addendum } - lazy val explanation: String = "" + def explain = "" } // Relative of CyclicReferenceInvolvingImplicit and RecursiveValueNeedsResultType class TermMemberNeedsResultTypeForImplicitSearch(cycleSym: Symbol)(implicit ctx: Context) extends CyclicMsg(TermMemberNeedsNeedsResultTypeForImplicitSearchID) { - lazy val msg: String = em"""$cycleSym needs result type because its right-hand side attempts implicit search""" - lazy val explanation: String = + def msg = em"""$cycleSym needs result type because its right-hand side attempts implicit search""" + def explain = em"""|The right hand-side of $cycleSym's definition requires an implicit search at the highlighted position. |To avoid this error, give `$cycleSym` an explicit type. |""".stripMargin } class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends SyntaxMsg(ClassCannotExtendEnumID) { - lazy val msg: String = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" - lazy val explanation: String = "" + def msg = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" + def explain = "" } class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends SyntaxMsg(NotAnExtractorID) { - lazy val msg: String = em"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method" - lazy val explanation: String = + def msg = em"$tree cannot be used as an extractor in a pattern because it lacks an unapply or unapplySeq method" + def explain = em"""|An ${hl("unapply")} method should be defined in an ${hl("object")} as follow: | - If it is just a test, return a ${hl("Boolean")}. For example ${hl("case even()")} | - If it returns a single sub-value of type T, return an ${hl("Option[T]")} @@ -2097,41 +2097,41 @@ object messages { class MemberWithSameNameAsStatic()(implicit val ctx: Context) extends SyntaxMsg(MemberWithSameNameAsStaticID) { - lazy val msg: String = em"Companion classes cannot define members with same name as a ${hl("@static")} member" - lazy val explanation: String = "" + def msg = em"Companion classes cannot define members with same name as a ${hl("@static")} member" + def explain = "" } class PureExpressionInStatementPosition(stat: untpd.Tree, val exprOwner: Symbol)(implicit ctx: Context) extends Message(PureExpressionInStatementPositionID) { - val kind = "Potential Issue" - lazy val msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" - lazy val explanation = + def kind = "Potential Issue" + def msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" + def explain = em"""The pure expression $stat doesn't have any side effect and its result is not assigned elsewhere. |It can be removed without changing the semantics of the program. This may indicate an error.""".stripMargin } class TraitCompanionWithMutableStatic()(implicit val ctx: Context) extends SyntaxMsg(TraitCompanionWithMutableStaticID) { - lazy val msg: String = em"Companion of traits cannot define mutable @static fields" - lazy val explanation: String = "" + def msg = em"Companion of traits cannot define mutable @static fields" + def explain = "" } class LazyStaticField()(implicit val ctx: Context) extends SyntaxMsg(LazyStaticFieldID) { - lazy val msg: String = em"Lazy @static fields are not supported" - lazy val explanation: String = "" + def msg = em"Lazy @static fields are not supported" + def explain = "" } class StaticOverridingNonStaticMembers()(implicit val ctx: Context) extends SyntaxMsg(StaticOverridingNonStaticMembersID) { - lazy val msg: String = em"${hl("@static")} members cannot override or implement non-static ones" - lazy val explanation: String = "" + def msg = em"${hl("@static")} members cannot override or implement non-static ones" + def explain = "" } class OverloadInRefinement(rsym: Symbol)(implicit val ctx: Context) extends DeclarationMsg(OverloadInRefinementID) { - lazy val msg: String = "Refinements cannot introduce overloaded definitions" - lazy val explanation: String = + def msg = "Refinements cannot introduce overloaded definitions" + def explain = em"""The refinement `$rsym` introduces an overloaded definition. |Refinements cannot contain overloaded definitions.""".stripMargin } @@ -2139,22 +2139,22 @@ object messages { class NoMatchingOverload(val alternatives: List[SingleDenotation], pt: Type)( err: Errors)(implicit val ctx: Context) extends TypeMismatchMsg(NoMatchingOverloadID) { - lazy val msg: String = + def msg = em"""None of the ${err.overloadedAltsStr(alternatives)} |match ${err.expectedTypeStr(pt)}""" - lazy val explanation: String = "" + def explain = "" } class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) extends TypeMsg(StableIdentPatternID) { - lazy val msg: String = + def msg = em"""Stable identifier required, but $tree found""" - lazy val explanation: String = "" + def explain = "" } class IllegalSuperAccessor(base: Symbol, memberName: Name, acc: Symbol, accTp: Type, other: Symbol, otherTp: Type)(implicit val ctx: Context) extends DeclarationMsg(IllegalSuperAccessorID) { - lazy val msg: String = { + def msg = { // The mixin containing a super-call that requires a super-accessor val accMixin = acc.owner // The class or trait that the super-accessor should resolve too in `base` @@ -2203,14 +2203,14 @@ object messages { | super-call to a specific parent, e.g. $staticSuperCall |""".stripMargin } - lazy val explanation: String = "" + def explain = "" } class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) extends DeclarationMsg(TraitParameterUsedAsParentPrefixID) { - lazy val msg: String = + def msg = s"${cls.show} cannot extend from a parent that is derived via its own parameters" - lazy val explanation: String = + def explain = ex""" |The parent class/trait that ${cls.show} extends from is obtained from |the parameter of ${cls.show}. This is disallowed in order to prevent @@ -2223,9 +2223,9 @@ object messages { class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) extends ReferenceMsg(UnknownNamedEnclosingClassOrObjectID) { - lazy val msg: String = + def msg = em"""no enclosing class or object is named '${hl(name.show)}'""" - lazy val explanation: String = + def explain = ex""" |The class or object named '${hl(name.show)}' was used as a visibility |modifier, but could not be resolved. Make sure that @@ -2236,22 +2236,22 @@ object messages { class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context) extends CyclicMsg(IllegalCyclicTypeReferenceID) { - lazy val msg: String = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" - lazy val explanation: String = "" + def msg = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" + def explain = "" } class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) extends SyntaxMsg(ErasedTypesCanOnlyBeFunctionTypesID) { - lazy val msg: String = "Types with erased keyword can only be function types `(erased ...) => ...`" - lazy val explanation: String = "" + def msg = "Types with erased keyword can only be function types `(erased ...) => ...`" + def explain = "" } class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) extends SyntaxMsg(CaseClassMissingNonImplicitParamListID) { - lazy val msg: String = + def msg = em"""|A ${hl("case class")} must have at least one non-implicit parameter list""" - lazy val explanation: String = + def explain = em"""|${cdef.name} must have at least one non-implicit parameter list, | if you're aiming to have a case class parametrized only by implicit ones, you should | add an explicit ${hl("()")} as a parameter list to ${cdef.name}.""".stripMargin @@ -2259,9 +2259,9 @@ object messages { class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context) extends SyntaxMsg(EnumerationsShouldNotBeEmptyID) { - lazy val msg: String = "Enumerations must contain at least one case" + def msg = "Enumerations must contain at least one case" - lazy val explanation: String = + def explain = em"""|Enumeration ${cdef.name} must contain at least one case |Example Usage: | ${hl("enum")} ${cdef.name} { @@ -2272,9 +2272,9 @@ object messages { class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context) extends SyntaxMsg(AbstractCannotBeUsedForObjectsID) { - lazy val msg: String = em"${hl("abstract")} modifier cannot be used for objects" + def msg = em"${hl("abstract")} modifier cannot be used for objects" - lazy val explanation: String = + def explain = em"""|Objects are final and cannot be extended, thus cannot have the ${hl("abstract")} modifier | |You may want to define an abstract class: @@ -2287,9 +2287,9 @@ object messages { class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context) extends SyntaxMsg(ModifierRedundantForObjectsID) { - lazy val msg: String = em"${hl(modifier)} modifier is redundant for objects" + def msg = em"${hl(modifier)} modifier is redundant for objects" - lazy val explanation: String = + def explain = em"""|Objects cannot be extended making the ${hl(modifier)} modifier redundant. |You may want to define the object without it: | ${hl("object")} ${mdef.name} { } @@ -2298,9 +2298,9 @@ object messages { class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) extends SyntaxMsg(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { - lazy val msg: String = i"explicit extends clause needed because both enum case and enum class have type parameters" + def msg = i"explicit extends clause needed because both enum case and enum class have type parameters" - lazy val explanation: String = + def explain = em"""Enumerations where the enum class as well as the enum case have type parameters need |an explicit extends. |for example: @@ -2312,9 +2312,8 @@ object messages { class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) extends SyntaxMsg(IllegalRedefinitionOfStandardKindID) { - lazy val msg: String = em"illegal redefinition of standard $kindType $name" - - lazy val explanation: String = + def msg = em"illegal redefinition of standard $kindType $name" + def explain = em"""| "$name" is a standard Scala core `$kindType` | Please choose a different name to avoid conflicts |""".stripMargin @@ -2322,9 +2321,8 @@ object messages { class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) extends SyntaxMsg(NoExtensionMethodAllowedID) { - lazy val msg: String = em"No extension method allowed here, since collective parameters are given" - - lazy val explanation: String = + def msg = em"No extension method allowed here, since collective parameters are given" + def explain = em"""|Extension method: | `${mdef}` |is defined inside an extension clause which has collective parameters. @@ -2333,9 +2331,9 @@ object messages { class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) extends SyntaxMsg(ExtensionMethodCannotHaveTypeParamsID) { - lazy val msg: String = i"Extension method cannot have type parameters since some were already given previously" + def msg = i"Extension method cannot have type parameters since some were already given previously" - lazy val explanation: String = + def explain = em"""|Extension method: | `${mdef}` |has type parameters `[${mdef.tparams.map(_.show).mkString(",")}]`, while the extension clause has @@ -2345,9 +2343,8 @@ object messages { class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) extends SyntaxMsg(ExtensionCanOnlyHaveDefsID) { - lazy val msg: String = em"Only methods allowed here, since collective parameters are given" - - lazy val explanation: String = + def msg = em"Only methods allowed here, since collective parameters are given" + def explain = em"""Extension clauses can only have `def`s | `${mdef.show}` is not a valid expression here. |""".stripMargin @@ -2355,9 +2352,8 @@ object messages { class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) extends SyntaxMsg(UnexpectedPatternForSummonFromID) { - lazy val msg: String = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" - - lazy val explanation: String = + def msg = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" + def explain = em"""|The pattern "${tree.show}" provided in the ${hl("case")} expression of the ${hl("summonFrom")}, | needs to be of the form ${hl("`x: T`")} or ${hl("`_`")}. | @@ -2375,9 +2371,8 @@ object messages { class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) extends SyntaxMsg(AnonymousInstanceCannotBeEmptyID) { - lazy val msg: String = i"anonymous instance must implement a type or have at least one extension method" - - lazy val explanation: String = + def msg = i"anonymous instance must implement a type or have at least one extension method" + def explain = em"""|Anonymous instances cannot be defined with an empty body. The block |`${impl.show}` should either contain an implemented type or at least one extension method. |""".stripMargin @@ -2385,9 +2380,8 @@ object messages { class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) extends SyntaxMsg(TypeSpliceInValPatternID) { - lazy val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead." - - lazy val explanation: String = + def msg = "Type splices cannot be used in val patterns. Consider using `match` instead." + def explain = em"""|Type splice: `$$${expr.show}` cannot be used in a `val` pattern. Consider rewriting the `val` pattern |as a `match` with a corresponding `case` to replace the `val`. |""".stripMargin @@ -2395,8 +2389,7 @@ object messages { class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) extends SyntaxMsg(ModifierNotAllowedForDefinitionID) { - lazy val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition" - - lazy val explanation: String = "" + def msg = s"Modifier `${flag.flagsString}` is not allowed for this definition" + def explain = "" } } diff --git a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala index 0a053db14ba1..dbc5861ab3d6 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -18,8 +18,8 @@ class TestMessageLaziness extends DottyTest { case class LazyError() extends Message(ErrorMessageID.LazyErrorId) { val kind = "Test" - lazy val msg = throw new Error("Didn't stay lazy.") - val explanation = "" + def msg = throw new Error("Didn't stay lazy.") + def explain = "" } @Test def assureLazy =