diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 91fe8f06daad..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 @@ -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/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 686102286668..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 @@ -750,11 +749,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..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._ @@ -2368,7 +2367,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 +2379,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/Symbols.scala b/compiler/src/dotty/tools/dotc/core/Symbols.scala index 0759fd2e1080..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 @@ -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..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 -import reporting.diagnostic.messages._ +import reporting.{Message, NoExplanation} +import reporting.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..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._ @@ -516,7 +515,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/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 9b00c9a87392..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 @@ -4650,19 +4649,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/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 17a0907184c2..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.MessageContainer +import reporting._ 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/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 479324873cdd..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) @@ -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/printing/Formatting.scala b/compiler/src/dotty/tools/dotc/printing/Formatting.scala index 25a6430b7d15..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.MessageContainer +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 MessageContainer._ + 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 0979e1c40dfa..6a7d21e827eb 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.MessageContainer -import diagnostic.messages.{ Error, ConditionalWarning } +import Diagnostic.{ Error, ConditionalWarning } /** * This class implements a Reporter that displays messages on a text console @@ -15,28 +14,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.msg, 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.msg, dia.pos, diagnosticLevel(dia))) true } - if (didPrint && ctx.shouldExplain(m)) - printMessage(explanation(m.contained)) - else if (didPrint && m.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 new file mode 100644 index 000000000000..1ab74c571697 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -0,0 +1,91 @@ +package dotty.tools +package dotc +package reporting + +import util.SourcePosition +import core.Contexts.Context +import config.Settings.Setting +import interfaces.Diagnostic.{ERROR, INFO, WARNING} + +import java.util.Optional + +object Diagnostic: + + def shouldExplain(dia: Diagnostic)(using ctx: Context): Boolean = + dia.msg.explanation.nonEmpty && ctx.settings.explain.value + + // `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 msg: Message, + val pos: SourcePosition, + val level: Int +) 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.replaceAll("\u001B\\[[;\\d]*m", "") + + 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/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 ba1ab9b33beb..0e6fe3fd8bb7 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.MessageContainer /** * This trait implements `isHidden` so that we avoid reporting non-sensical messages. @@ -12,9 +11,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.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 new file mode 100644 index 000000000000..25343fb26419 --- /dev/null +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -0,0 +1,136 @@ +package dotty.tools +package dotc +package reporting + +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 + */ + implicit def toNoExplanation(str: => String): Message = + 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 `Diagnostic` which contains the log level and can later be + * consumed by a subclass of `Reporter`. However, the error position is only + * 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 + * persisting these will result in a memory leak. + * + * Instead use the `persist` method to create an instance that does not keep a + * reference to these contexts. + * + * @param errorId a unique id identifying the message, this will later be + * used to reference documentation online + */ +abstract class Message(val errorId: ErrorMessageID) { self => + import Message._ + + /** The `msg` contains the diagnostic message e.g: + * + * > expected: String + * > found: Int + * + * This message will be placed underneath the position given by the enclosing + * `Diagnostic`. The message is given in raw form, with possible embedded + * tags. + */ + protected def msg: String + + /** 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. It might contain embedded tags. + */ + 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 */ + 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 + * 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 + * that was captured in the original message. + */ + def persist: Message = new Message(errorId) { + 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 + def msg = f(self.msg) + def explain = self.explain + + def appendExplanation(suffix: => String): Message = new Message(errorId): + 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) { + def msg: String = msgFn + def explain: String = "" + val kind: String = "" + + override def toString(): String = msg +} + +/** The extractor for `NoExplanation` can be used to check whether any error + * lacks an explanation + */ +object NoExplanation { + def unapply(m: Message): Option[Message] = + if (m.explanation == "") Some(m) + else None +} diff --git a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala index ef912c3bf61e..c37226d29b1a 100644 --- a/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala +++ b/compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -8,8 +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.messages._ +import Diagnostic._ import util.SourcePosition import scala.internal.Chars.{ LF, CR, FF, SU } import scala.annotation.switch @@ -152,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 } @@ -167,14 +166,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 2a4ca680496e..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.messages._ -import diagnostic._ +import Diagnostic._ import ast.{tpd, Trees} import Message._ import core.Decorators._ @@ -25,20 +24,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) @@ -87,16 +86,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 +119,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 +138,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. @@ -198,7 +191,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 @@ -267,25 +260,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 = { @@ -313,7 +306,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 ? @@ -322,12 +315,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..cb1e020df7e3 100644 --- a/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -5,8 +5,7 @@ package reporting import core.Contexts.Context import collection.mutable import config.Printers.typr -import diagnostic.MessageContainer -import diagnostic.messages._ +import Diagnostic._ /** This class implements a Reporter that stores all messages * @@ -20,12 +19,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 +33,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..6668b0c49fea 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ThrowingReporter.scala @@ -3,16 +3,15 @@ package dotc package reporting import core.Contexts.Context -import diagnostic.MessageContainer -import diagnostic.messages.Error +import Diagnostic.Error /** * This class implements a Reporter that throws all errors and sends warnings and other * 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..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.MessageContainer /** This trait implements `isHidden` so that multiple messages per position * are suppressed, unless they are of increasing severity. */ @@ -16,14 +15,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/Message.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala deleted file mode 100644 index b3b9a12067ad..000000000000 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/Message.scala +++ /dev/null @@ -1,142 +0,0 @@ -package dotty.tools -package dotc -package reporting -package diagnostic - -import util.SourcePosition - -import messages._ - -object Message { - /** 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 - */ - implicit def toNoExplanation(str: String): Message = - new 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 - * consumed by a subclass of `Reporter`. However, the error position is only - * part of `MessageContainer`, 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 - * persisting these will result in a memory leak. - * - * Instead use the `persist` method to create an instance that does not keep a - * reference to these contexts. - * - * @param errorId a unique id identifying the message, this will later be - * used to reference documentation online - */ -abstract class Message(val errorId: ErrorMessageID) { self => - - /** The `msg` contains the diagnostic message e.g: - * - * > expected: String - * > found: Int - * - * This message will be placed underneath the position given by the enclosing - * `MessageContainer` - */ - def msg: String - - /** The kind of the error message is something like "Syntax" or "Type - * Mismatch" - */ - 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. - */ - 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. - */ - 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) - - /** Enclose this message in an `Warning` container */ - def warning(pos: SourcePosition): Warning = - new Warning(toMessage, pos) - - /** 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) -} - -/** The fallback `Message` containing no explanation and having no `kind` */ -class NoExplanation(val msg: String) extends Message(ErrorMessageID.NoExplanationID) { - val explanation: String = "" - val kind: String = "" - - override def toString(): String = msg -} - -/** The extractor for `NoExplanation` can be used to check whether any error - * lacks an explanation - */ -object NoExplanation { - def unapply(m: Message): Option[Message] = - if (m.explanation == "") Some(m) - else None -} diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala deleted file mode 100644 index af0541556a8a..000000000000 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/MessageContainer.scala +++ /dev/null @@ -1,75 +0,0 @@ -package dotty.tools -package dotc -package reporting -package diagnostic - -import util.SourcePosition -import core.Contexts.Context - -import java.util.Optional - -object MessageContainer { - val nonSensicalStartTag: String = "" - val nonSensicalEndTag: String = "" - - implicit class MessageContext(val c: Context) extends AnyVal { - def shouldExplain(cont: MessageContainer): Boolean = { - implicit val ctx = c - cont.contained.explanation match { - case "" => false - case _ => ctx.settings.explain.value - } - } - } -} - -class MessageContainer( - msgFn: => Message, - val pos: SourcePosition, - val level: Int -) extends Exception with interfaces.Diagnostic { - import MessageContainer._ - private var myMsg: String = null - private var myIsNonSensical: Boolean = false - private var myContained: Message = null - - override def position: Optional[interfaces.SourcePosition] = - if (pos.exists && pos.source.exists) Optional.of(pos) else Optional.empty() - - /** 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 - } - - /** 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 - * 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 getMessage(): String = message -} diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala similarity index 55% rename from compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala rename to compiler/src/dotty/tools/dotc/reporting/messages.scala index 5b57e7ec8a7e..0b5f1c40980c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -1,109 +1,40 @@ package dotty.tools 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 +/** 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 { - // `MessageContainer`s to be consumed by `Reporter` ---------------------- // - class Error( - msgFn: => Message, - pos: SourcePosition - ) extends MessageContainer(msgFn, 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, - pos: SourcePosition - ) extends Error(msgFn, pos) - - class Warning( - msgFn: => Message, - pos: SourcePosition - ) extends MessageContainer(msgFn, pos, WARNING) { - def toError: Error = new Error(msgFn, pos) - } - - class Info( - msgFn: => Message, - pos: SourcePosition - ) extends MessageContainer(msgFn, pos, INFO) - - abstract class ConditionalWarning( - msgFn: => Message, - pos: SourcePosition - ) extends Warning(msgFn, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] - } - - class FeatureWarning( - msgFn: => Message, - pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.feature - } - - class UncheckedWarning( - msgFn: => Message, - pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.unchecked - } - - class DeprecationWarning( - msgFn: => Message, - pos: SourcePosition - ) extends ConditionalWarning(msgFn, pos) { - def enablingOption(implicit ctx: Context): Setting[Boolean] = ctx.settings.deprecation - } - - class MigrationWarning( - msgFn: => Message, - pos: SourcePosition - ) extends ConditionalWarning(msgFn, 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 @@ -113,11 +44,41 @@ 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): + def kind = "Syntax" + + abstract class TypeMsg(errorId: ErrorMessageID) extends Message(errorId): + def kind = "Type" + + abstract class TypeMismatchMsg(errorId: ErrorMessageID) extends Message(errorId): + def kind = "Type Mismatch" + + abstract class NamingMsg(errorId: ErrorMessageID) extends Message(errorId): + def kind = "Naming" + + abstract class DeclarationMsg(errorId: ErrorMessageID) extends Message(errorId): + 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): + def kind = "Not Found" + def name: Name + + abstract class PatternMatchMsg(errorId: ErrorMessageID) extends Message(errorId): + def kind = "Pattern Match" + + abstract class CyclicMsg(errorId: ErrorMessageID) extends Message(errorId): + def kind = "Cyclic" + + abstract class ReferenceMsg(errorId: ErrorMessageID) extends Message(errorId): + def kind = "Reference" - // Syntax Errors ---------------------------------------------------------- // abstract class EmptyCatchOrFinallyBlock(tryBody: untpd.Tree, errNo: ErrorMessageID)(implicit ctx: Context) - extends Message(EmptyCatchOrFinallyBlockID) { - val explanation: String = { + extends SyntaxMsg(EmptyCatchOrFinallyBlockID) { + def explain = { val tryString = tryBody match { case Block(Nil, untpd.EmptyTree) => "{}" case _ => tryBody.show @@ -151,54 +112,48 @@ 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" - 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""" } - 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" - 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.""" } - case class DeprecatedWithOperator()(implicit ctx: Context) - extends Message(DeprecatedWithOperatorID) { - val kind: String = "Syntax" - val msg: String = + class DeprecatedWithOperator()(implicit ctx: Context) + extends SyntaxMsg(DeprecatedWithOperatorID) { + def msg = em"""${hl("with")} as a type operator has been deprecated; use ${hl("&")} instead""" - 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")}.""" } - case class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(CaseClassMissingParamListID) { - val kind: String = "Syntax" - val msg: String = + class CaseClassMissingParamList(cdef: untpd.TypeDef)(implicit ctx: Context) + extends SyntaxMsg(CaseClassMissingParamListID) { + def msg = em"""|A ${hl("case class")} must have at least one parameter list""" - 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}.""" } - case class AnonymousFunctionMissingParamType(param: untpd.ValDef, - args: List[untpd.Tree], - tree: untpd.Function, - pt: Type) - (implicit ctx: Context) - extends Message(AnonymousFunctionMissingParamTypeID) { - val kind: String = "Type" - - val msg: String = { + class AnonymousFunctionMissingParamType(param: untpd.ValDef, + args: List[untpd.Tree], + tree: untpd.Function, + pt: Type) + (implicit ctx: Context) + extends TypeMsg(AnonymousFunctionMissingParamTypeID) { + def msg = { val ofFun = if (MethodType.syntheticParamNames(args.length + 1) contains param.name) i" of expanded function:\n$tree" @@ -214,31 +169,28 @@ object messages { |I could not infer the type of the parameter ${param.name}$ofFun.$inferred""" } - val explanation: String = "" + def explain = "" } - 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 + class WildcardOnTypeArgumentNotAllowedOnNew()(implicit ctx: Context) + extends SyntaxMsg(WildcardOnTypeArgumentNotAllowedOnNewID) { + def msg = "Type argument must be fully defined" + def explain = + 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: @@ -252,12 +204,11 @@ object messages { // Type Errors ------------------------------------------------------------ // - 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}" + class DuplicateBind(bind: untpd.Bind, tree: untpd.CaseDef)(implicit ctx: Context) + extends NamingMsg(DuplicateBindID) { + def msg = em"duplicate pattern variable: ${bind.name}" - val explanation: String = { + def explain = { val pat = tree.pat.show val guard = tree.guard match { case untpd.EmptyTree => "" @@ -279,12 +230,10 @@ 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" - - val explanation: String = { + class MissingIdent(tree: untpd.Ident, treeKind: String, val name: Name)(implicit ctx: Context) + extends NotFoundMsg(MissingIdentID) { + 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 @@ -292,27 +241,57 @@ 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 = { - val (where, printCtx) = Formatting.disambiguateTypes(found, expected) + class TypeMismatch(found: Type, expected: Type, addendum: => String = "")(implicit ctx: Context) + 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 + // 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) + + def msg = + 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 - val explanation: String = "" - } - - case class NotAMember(site: Type, name: Name, selected: String, addendum: String = "")(implicit ctx: Context) - extends Message(NotAMemberID) { - val kind: String = "Member Not Found" + 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 - 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 @@ -364,15 +343,14 @@ object messages { ex"$selected $name is not a member of ${site.widen}$finalAddendum" } - val explanation: String = "" + def explain = "" } - 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" + class EarlyDefinitionsNotSupported()(implicit ctx: Context) + extends SyntaxMsg(EarlyDefinitionsNotSupportedID) { + def msg = "Early definitions are not supported; use trait parameters instead" - val explanation: String = { + def explain = { val code1 = """|trait Logging { | val f: File @@ -413,12 +391,11 @@ 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""" + class TopLevelImplicitClass(cdef: untpd.TypeDef)(implicit ctx: Context) + extends SyntaxMsg(TopLevelImplicitClassID) { + def msg = em"""An ${hl("implicit class")} may not be top-level""" - val explanation: String = { + def explain = { val TypeDef(name, impl @ Template(constr0, parents, self, _)) = cdef val exampleArgs = if(constr0.vparamss.isEmpty) "..." @@ -444,12 +421,11 @@ 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")}""" + class ImplicitCaseClass(cdef: untpd.TypeDef)(implicit ctx: Context) + extends SyntaxMsg(ImplicitCaseClassID) { + def msg = em"""A ${hl("case class")} may not be defined as ${hl("implicit")}""" - val explanation: String = + def explain = em"""|Implicit classes may not be case classes. Instead use a plain class: | |implicit class ${cdef.name}... @@ -457,11 +433,10 @@ object messages { |""" + implicitClassRestrictionsText } - 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 = { + class ImplicitClassPrimaryConstructorArity()(implicit ctx: Context) + extends SyntaxMsg(ImplicitClassPrimaryConstructorArityID){ + 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: | @@ -473,12 +448,11 @@ 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")}""" + class ObjectMayNotHaveSelfType(mdef: untpd.ModuleDef)(implicit ctx: Context) + extends SyntaxMsg(ObjectMayNotHaveSelfTypeID) { + def msg = em"""${hl("object")}s must not have a self ${hl("type")}""" - 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")}: @@ -491,12 +465,11 @@ object messages { } } - case class RepeatedModifier(modifier: String)(implicit ctx:Context) - extends Message(RepeatedModifierID) { - val kind: String = "Syntax" - val msg: String = em"""Repeated modifier $modifier""" + class RepeatedModifier(modifier: String)(implicit ctx:Context) + extends SyntaxMsg(RepeatedModifierID) { + def msg = em"""Repeated modifier $modifier""" - 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. @@ -513,11 +486,10 @@ 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 = { + class InterpolatedStringError()(implicit ctx:Context) + extends SyntaxMsg(InterpolatedStringErrorID) { + 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. @@ -531,11 +503,10 @@ 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 = + class UnboundPlaceholderParameter()(implicit ctx:Context) + extends SyntaxMsg(UnboundPlaceholderParameterID) { + 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. | @@ -567,20 +538,18 @@ 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 = { + class IllegalStartSimpleExpr(illegalToken: String)(implicit ctx: Context) + extends SyntaxMsg(IllegalStartSimpleExprID) { + def msg = em"expression expected but ${Red(illegalToken)} found" + def explain = { em"""|An expression cannot start with ${Red(illegalToken)}.""" } } - case class MissingReturnType()(implicit ctx:Context) - extends Message(MissingReturnTypeID) { - val kind: String = "Syntax" - val msg: String = "Missing return type" - val explanation: String = + class MissingReturnType()(implicit ctx:Context) + extends SyntaxMsg(MissingReturnTypeID) { + def msg = "Missing return type" + def explain = em"""|An abstract declaration must have a return type. For example: | |trait Shape {hl( @@ -588,23 +557,21 @@ 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 = + class MissingReturnTypeWithReturnStatement(method: Symbol)(implicit ctx: Context) + extends SyntaxMsg(MissingReturnTypeWithReturnStatementID) { + 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: | |${hl("def good: Int /* explicit return type */ = return 1")}""" } - case class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) - extends Message(YieldOrDoExpectedInForComprehensionID) { - val kind: String = "Syntax" - val msg: String = em"${hl("yield")} or ${hl("do")} expected" + class YieldOrDoExpectedInForComprehension()(implicit ctx: Context) + extends SyntaxMsg(YieldOrDoExpectedInForComprehensionID) { + def msg = em"${hl("yield")} or ${hl("do")} expected" - 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. @@ -632,12 +599,12 @@ object messages { |""" } - case class ProperDefinitionNotFound()(implicit ctx: Context) + 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")}""" + def kind: String = "Doc Comment" + def msg = em"""Proper definition was not found in ${hl("@usecase")}""" - val explanation: String = { + def explain = { val noUsecase = "def map[B, That](f: A => B)(implicit bf: CanBuildFrom[List[A], B, That]): That" @@ -671,12 +638,11 @@ 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." + class ByNameParameterNotSupported(tpe: untpd.TypTree)(implicit ctx: Context) + extends SyntaxMsg(ByNameParameterNotSupportedID) { + def msg = em"By-name parameter type ${tpe} not allowed here." - 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. | @@ -695,37 +661,28 @@ object messages { |""" } - case class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) - extends Message(WrongNumberOfTypeArgsID) { - val kind: String = "Syntax" + class WrongNumberOfTypeArgs(fntpe: Type, expectedArgs: List[ParamInfo], actual: List[untpd.Tree])(implicit ctx: Context) + extends SyntaxMsg(WrongNumberOfTypeArgsID) { private val expectedCount = expectedArgs.length 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 { + def msg = + 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 = { + def explain = { val tooManyTypeParams = """|val tuple2: (Int, String) = (1, "one") |val list: List[(Int, String)] = List(tuple2)""".stripMargin @@ -745,11 +702,10 @@ 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 = { + class IllegalVariableInPatternAlternative()(implicit ctx: Context) + extends SyntaxMsg(IllegalVariableInPatternAlternativeID) { + 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 @@ -774,11 +730,10 @@ 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 = { + class IdentifierExpected(identifier: String)(implicit ctx: Context) + extends SyntaxMsg(IdentifierExpectedID) { + 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 @@ -795,11 +750,10 @@ 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 = + class AuxConstructorNeedsNonImplicitParameter()(implicit ctx:Context) + extends SyntaxMsg(AuxConstructorNeedsNonImplicitParameterID) { + 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 @@ -811,11 +765,10 @@ object messages { |""" } - case class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) - extends Message(IncorrectRepeatedParameterSyntaxID) { - val kind: String = "Syntax" - val msg: String = "'*' expected" - val explanation: String = + class IncorrectRepeatedParameterSyntax()(implicit ctx: Context) + extends SyntaxMsg(IncorrectRepeatedParameterSyntaxID) { + def msg = "'*' expected" + def explain = em"""|Expected * in ${hl("_*")} operator. | |The ${hl("_*")} operator can be used to supply a sequence-based argument @@ -838,11 +791,10 @@ object messages { |""".stripMargin } - case class IllegalLiteral()(implicit ctx: Context) - extends Message(IllegalLiteralID) { - val kind: String = "Syntax" - val msg: String = "Illegal literal" - val explanation: String = + class IllegalLiteral()(implicit ctx: Context) + extends SyntaxMsg(IllegalLiteralID) { + 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 @@ -853,16 +805,17 @@ 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" - val msg: String = + def kind = "Pattern Match Exhaustivity" + lazy val uncovered = uncoveredFn + def msg = em"""|${hl("match")} may not be exhaustive. | |It would fail on pattern case: $uncovered""" - 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 @@ -870,11 +823,10 @@ object messages { |""" } - case class UncheckedTypePattern(msg: String)(implicit ctx: Context) - extends Message(UncheckedTypePatternID) { - val kind: String = "Pattern Match Exhaustivity" - - val explanation: String = + class UncheckedTypePattern(msgFn: => String)(implicit ctx: Context) + extends PatternMatchMsg(UncheckedTypePatternID) { + 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. | @@ -882,25 +834,23 @@ object messages { |""" } - case class MatchCaseUnreachable()(implicit ctx: Context) + class MatchCaseUnreachable()(implicit ctx: Context) extends Message(MatchCaseUnreachableID) { - val kind: String = "Match case Unreachable" - val msg: String = "Unreachable case" - val explanation: String = "" + def kind = "Match case Unreachable" + def msg = "Unreachable case" + def explain = "" } - 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 = "" + class MatchCaseOnlyNullWarning()(implicit ctx: Context) + extends PatternMatchMsg(MatchCaseOnlyNullWarningID) { + def msg = em"""Only ${hl("null")} is matched. Consider using ${hl("case null =>")} instead.""" + def explain = "" } - 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 = { + class SeqWildcardPatternPos()(implicit ctx: Context) + extends SyntaxMsg(SeqWildcardPatternPosID) { + 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 @@ -920,11 +870,10 @@ object messages { } } - case class IllegalStartOfSimplePattern()(implicit ctx: Context) - extends Message(IllegalStartOfSimplePatternID) { - val kind: String = "Syntax" - val msg: String = "pattern expected" - val explanation: String = { + class IllegalStartOfSimplePattern()(implicit ctx: Context) + extends SyntaxMsg(IllegalStartOfSimplePatternID) { + def msg = "pattern expected" + def explain = { val sipCode = """def f(x: Int, y: Int) = x match { | case `y` => ... @@ -1000,20 +949,18 @@ 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 = "" + class PkgDuplicateSymbol(existing: Symbol)(implicit ctx: Context) + extends NamingMsg(PkgDuplicateSymbolID) { + def msg = em"Trying to define package with same name as $existing" + def explain = "" } - case class ExistentialTypesNoLongerSupported()(implicit ctx: Context) - extends Message(ExistentialTypesNoLongerSupportedID) { - val kind: String = "Syntax" - val msg: String = + class ExistentialTypesNoLongerSupported()(implicit ctx: Context) + extends SyntaxMsg(ExistentialTypesNoLongerSupportedID) { + def msg = em"""|Existential types are no longer supported - |use a wildcard or dependent type instead""" - val explanation: String = + def explain = em"""|The use of existential types is no longer supported. | |You should use a wildcard or dependent type instead. @@ -1030,11 +977,10 @@ object messages { |""" } - case class UnboundWildcardType()(implicit ctx: Context) - extends Message(UnboundWildcardTypeID) { - val kind: String = "Syntax" - val msg: String = "Unbound wildcard type" - val explanation: String = + class UnboundWildcardType()(implicit ctx: Context) + extends SyntaxMsg(UnboundWildcardTypeID) { + 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")}. @@ -1075,28 +1021,23 @@ 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 = + class DanglingThisInPath()(implicit ctx: Context) extends SyntaxMsg(DanglingThisInPathID) { + def msg = em"""Expected an additional member selection after the keyword ${hl("this")}""" + def explain = + 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 @@ -1111,26 +1052,22 @@ object messages { |""" } - case class OverridesNothing(member: Symbol)(implicit ctx: Context) - extends Message(OverridesNothingID) { - val kind: String = "Reference" - val msg: String = em"""${member} overrides nothing""" + class OverridesNothing(member: Symbol)(implicit ctx: Context) + extends DeclarationMsg(OverridesNothingID) { + def msg = em"""${member} overrides nothing""" - 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? |""" } - 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 = + class OverridesNothingButNameExists(member: Symbol, existing: List[Denotations.SingleDenotation])(implicit ctx: Context) + extends DeclarationMsg(OverridesNothingButNameExistsID) { + 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. | @@ -1142,12 +1079,11 @@ 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}" + class ForwardReferenceExtendsOverDefinition(value: Symbol, definition: Symbol)(implicit ctx: Context) + extends ReferenceMsg(ForwardReferenceExtendsOverDefinitionID) { + def msg = em"${definition.name} is a forward reference extending over the definition of ${value.name}" - 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}. | @@ -1161,34 +1097,32 @@ object messages { |""".stripMargin } - case class ExpectedTokenButFound(expected: Token, found: Token)(implicit ctx: Context) - extends Message(ExpectedTokenButFoundID) { - val kind: String = "Syntax" + class ExpectedTokenButFound(expected: Token, found: Token)(implicit ctx: Context) + extends SyntaxMsg(ExpectedTokenButFoundID) { - private val expectedText = - if (Tokens.isIdentifier(expected)) "an identifier" - else Tokens.showToken(expected) + private lazy val foundText = Tokens.showToken(found) - private val foundText = Tokens.showToken(found) + def msg = + val expectedText = + if (Tokens.isIdentifier(expected)) "an identifier" + else Tokens.showToken(expected) + em"""${expectedText} expected, but ${foundText} found""" - val msg: String = em"""${expectedText} expected, but ${foundText} found""" - - private val ifKeyword = + def explain = 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 = + class MixedLeftAndRightAssociativeOps(op1: Name, op2: Name, op2LeftAssoc: Boolean)(implicit ctx: Context) + extends SyntaxMsg(MixedLeftAndRightAssociativeOpsID) { + 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" + 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"} @@ -1216,12 +1150,11 @@ object messages { |""".stripMargin } - 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 = + class CantInstantiateAbstractClassOrTrait(cls: Symbol, isTrait: Boolean)(implicit ctx: Context) + extends TypeMsg(CantInstantiateAbstractClassOrTraitID) { + private val traitOrAbstract = if (isTrait) "a trait" else "abstract" + 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. | @@ -1235,19 +1168,17 @@ object messages { |""".stripMargin } - 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 = + class UnreducibleApplication(tycon: Type)(using Context) extends TypeMsg(UnreducibleApplicationID): + 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.""" - 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 = + class OverloadedOrRecursiveMethodNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) + extends CyclicMsg(OverloadedOrRecursiveMethodNeedsResultTypeID) { + 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. @@ -1258,32 +1189,30 @@ object messages { |""".stripMargin } - 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 = + class RecursiveValueNeedsResultType(cycleSym: Symbol)(implicit ctx: Context) + extends CyclicMsg(RecursiveValueNeedsResultTypeID) { + def msg = em"""Recursive $cycleSym needs type""" + def explain = em"""The definition of $cycleSym is recursive and you need to specify its type. |""".stripMargin } - 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 = + class CyclicReferenceInvolving(denot: SymDenotation)(implicit ctx: Context) + extends CyclicMsg(CyclicReferenceInvolvingID) { + def msg = + val where = if denot.exists then s" involving $denot" else "" + em"Cyclic reference$where" + 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. |""".stripMargin } - 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 = + class CyclicReferenceInvolvingImplicit(cycleSym: Symbol)(implicit ctx: Context) + extends CyclicMsg(CyclicReferenceInvolvingImplicitID) { + 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. @@ -1291,15 +1220,11 @@ object messages { |""".stripMargin } - 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 = + class SuperQualMustBeParent(qual: untpd.Ident, cls: ClassSymbol)(implicit ctx: Context) + extends ReferenceMsg(SuperQualMustBeParentID) { + 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")}. | @@ -1308,11 +1233,10 @@ object messages { |""".stripMargin } - 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 = + class VarArgsParamMustComeLast()(implicit ctx: Context) + extends SyntaxMsg(IncorrectRepeatedParameterSyntaxID) { + 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. |""" @@ -1320,8 +1244,8 @@ object messages { import typer.Typer.BindingPrec - case class AmbiguousImport(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec, prevCtx: Context)(implicit ctx: Context) - extends Message(AmbiguousImportID) { + class AmbiguousImport(name: Name, newPrec: BindingPrec, prevPrec: BindingPrec, prevCtx: Context)(implicit ctx: Context) + extends ReferenceMsg(AmbiguousImportID) { /** A string which explains how something was bound; Depending on `prec` this is either * imported by @@ -1341,15 +1265,12 @@ object messages { ex"""$howVisible$qualifier in ${em"${whereFound.owner}"}""" } - - val msg: String = + def msg = 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 = + def explain = em"""|The compiler can't decide which of the possible choices you |are referencing with $name. |Note: @@ -1360,20 +1281,18 @@ object messages { |""" } - case class MethodDoesNotTakeParameters(tree: tpd.Tree)(implicit ctx: Context) - extends Message(MethodDoesNotTakeParametersId) { - val kind: String = "Reference" - + class MethodDoesNotTakeParameters(tree: tpd.Tree)(implicit ctx: Context) + extends TypeMsg(MethodDoesNotTakeParametersId) { def methodSymbol: Symbol = tpd.methPart(tree).symbol - 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" } - val explanation: String = { + def explain = { val isNullary = methodSymbol.info.isInstanceOf[ExprType] val addendum = if (isNullary) "\nNullary methods may not be called with parenthesis" @@ -1384,18 +1303,16 @@ 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) { - - private val all = if (alts.length == 2) "both" else "all" - val msg: String = - s"""|Ambiguous overload. The ${err.overloadedAltsStr(alts)} + extends ReferenceMsg(AmbiguousOverloadID) { + private def all = if (alternatives.length == 2) "both" else "all" + def msg = + s"""|Ambiguous overload. The ${err.overloadedAltsStr(alternatives)} |$all match ${err.expectedTypeStr(pt)}""".stripMargin - val kind: String = "Reference" - val explanation: String = - em"""|There are ${alts.length} methods that could be referenced as the compiler knows too little + 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 |- assigning it to a value with a specified type, or @@ -1403,11 +1320,10 @@ 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 = + class ReassignmentToVal(name: Name)(implicit ctx: Context) + extends TypeMsg(ReassignmentToValID) { + 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")} @@ -1417,37 +1333,32 @@ object messages { |""".stripMargin } - 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 = + class TypeDoesNotTakeParameters(tpe: Type, params: List[Trees.Tree[Trees.Untyped]])(implicit ctx: Context) + extends TypeMsg(TypeDoesNotTakeParametersID) { + 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(", ")}" i"""You specified ${NoColor(ps)} for ${em"$tpe"}, which is not |declared to take any. |""" } - 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 = + class ParameterizedTypeLacksArguments(psym: Symbol)(implicit ctx: Context) + extends TypeMsg(ParameterizedTypeLacksArgumentsID) { + 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. |""" } - 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 = + class VarValParametersMayNotBeCallByName(name: TermName, mutable: Boolean)(implicit ctx: Context) + extends SyntaxMsg(VarValParametersMayNotBeCallByNameID) { + def varOrVal = if (mutable) em"${hl("var")}" else em"${hl("val")}" + 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 @@ -1457,40 +1368,36 @@ object messages { |""" } - case class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) - extends Message(MissingTypeParameterForID) { - val msg: String = + class MissingTypeParameterFor(tpe: Type)(implicit ctx: Context) + extends SyntaxMsg(MissingTypeParameterForID) { + def msg = 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 = "" + def explain = "" } - 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" + class MissingTypeParameterInTypeApp(tpe: Type)(implicit ctx: Context) + extends TypeMsg(MissingTypeParameterInTypeAppID) { + def numParams = tpe.typeParams.length + def parameters = if (numParams == 1) "parameter" else "parameters" + def msg = em"Missing type $parameters for $tpe" + def explain = 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 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 = "" + extends TypeMismatchMsg(DoesNotConformToBoundID) { + def msg = em"Type argument ${tpe} does not conform to $which bound $bound${err.whyNoMatchStr(tpe, bound)}" + def explain = "" } - 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) { - val msg: String = em"""$category: self type $selfType of $cls does not conform to self type $otherSelf + extends TypeMismatchMsg(DoesNotConformToSelfTypeID) { + def msg = 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 = + def explain = em"""You mixed in $other which requires self type $otherSelf, but $cls has self type |$selfType and does not inherit from $otherSelf. | @@ -1499,12 +1406,11 @@ object messages { """ } - case class DoesNotConformToSelfTypeCantBeInstantiated(tp: Type, selfType: Type)( + 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 = + extends TypeMismatchMsg(DoesNotConformToSelfTypeCantBeInstantiatedID) { + 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 @@ -1512,87 +1418,78 @@ object messages { |""" } - case class AbstractMemberMayNotHaveModifier(sym: Symbol, flag: FlagSet)( + 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 = "" + extends SyntaxMsg(AbstractMemberMayNotHaveModifierID) { + def msg = em"""${hl("abstract")} $sym may not have `${flag.flagsString}` modifier""" + def explain = "" } - case class TopLevelCantBeImplicit(sym: Symbol)( + 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 = "" + extends SyntaxMsg(TopLevelCantBeImplicitID) { + def msg = em"""${hl("implicit")} modifier cannot be used for top-level definitions""" + def explain = "" } - 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 = "" + class TypesAndTraitsCantBeImplicit()(implicit ctx: Context) + extends SyntaxMsg(TypesAndTraitsCantBeImplicitID) { + def msg = em"""${hl("implicit")} modifier cannot be used for types or traits""" + def explain = "" } - case class OnlyClassesCanBeAbstract(sym: Symbol)( + 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 = "" + extends SyntaxMsg(OnlyClassesCanBeAbstractID) { + def explain = "" + def msg = 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 msg: String = em"""${hl("abstract override")} modifier only allowed for members of traits""" - val kind: String = "Syntax" - val explanation: String = "" + extends SyntaxMsg(AbstractOverrideOnlyInTraitsID) { + def msg = em"""${hl("abstract override")} modifier only allowed for members of traits""" + def explain = "" } - case class TraitsMayNotBeFinal(sym: Symbol)( + 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 = + extends SyntaxMsg(TraitsMayNotBeFinalID) { + 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." } - case class NativeMembersMayNotHaveImplementation(sym: Symbol)( + 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 = "" + extends SyntaxMsg(NativeMembersMayNotHaveImplementationID) { + def msg = em"""${hl("@native")} members may not have an implementation""" + def explain = "" } - case class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( + class OnlyClassesCanHaveDeclaredButUndefinedMembers(sym: Symbol)( implicit ctx: Context) - extends Message(OnlyClassesCanHaveDeclaredButUndefinedMembersID) { + extends SyntaxMsg(OnlyClassesCanHaveDeclaredButUndefinedMembersID) { - 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" + def msg = em"""Declaration of $sym not allowed here: only classes can have declared but undefined members""" + def explain = 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 = + class CannotExtendAnyVal(sym: Symbol)(implicit ctx: Context) + extends SyntaxMsg(CannotExtendAnyValID) { + 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")}. |""" } - case class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(implicit ctx: Context) - extends Message(CannotHaveSameNameAsID) { + class CannotHaveSameNameAs(sym: Symbol, cls: Symbol, reason: CannotHaveSameNameAs.Reason)(implicit ctx: Context) + extends SyntaxMsg(CannotHaveSameNameAsID) { import CannotHaveSameNameAs._ def reasonMessage: String = reason match { case CannotBeOverridden => "class definitions cannot be overridden" @@ -1602,9 +1499,8 @@ object messages { |""".stripMargin } - val msg: String = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage - val kind: String = "Syntax" - val explanation: String = "" + def msg = em"""$sym cannot have the same name as ${cls.showLocated} -- """ + reasonMessage + def explain = "" } object CannotHaveSameNameAs { sealed trait Reason @@ -1612,166 +1508,145 @@ object messages { case class DefinedInSelf(self: tpd.ValDef) extends Reason } - 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 = "" + class ValueClassesMayNotDefineInner(valueClass: Symbol, inner: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotDefineInnerID) { + def msg = em"""Value classes may not define an inner class""" + def explain = "" } - 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 = "" + class ValueClassesMayNotDefineNonParameterField(valueClass: Symbol, field: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotDefineNonParameterFieldID) { + def msg = em"""Value classes may not define non-parameter field""" + def explain = "" } - 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 = "" + class ValueClassesMayNotDefineASecondaryConstructor(valueClass: Symbol, constructor: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotDefineASecondaryConstructorID) { + def msg = em"""Value classes may not define a secondary constructor""" + def explain = "" } - 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 = "" + class ValueClassesMayNotContainInitalization(valueClass: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotContainInitalizationID) { + def msg = em"""Value classes may not contain initialization statements""" + def explain = "" } - 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 = "" + class ValueClassesMayNotBeAbstract(valueClass: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotBeAbstractID) { + def msg = em"""Value classes may not be ${hl("abstract")}""" + def explain = "" } - 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 = "" + class ValueClassesMayNotBeContainted(valueClass: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotBeContaintedID) { + private def localOrMember = if (valueClass.owner.isTerm) "local class" else "member of another class" + def msg = s"""Value classes may not be a $localOrMember""" + def explain = "" } - 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 = "" + class ValueClassesMayNotWrapItself(valueClass: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassesMayNotWrapItselfID) { + def msg = """A value class may not wrap itself""" + def explain = "" } - 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 = + class ValueClassParameterMayNotBeAVar(valueClass: Symbol, param: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassParameterMayNotBeAVarID) { + 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.""" } - 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 = "" + class ValueClassNeedsOneValParam(valueClass: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassNeedsExactlyOneValParamID) { + def msg = em"""Value class needs one ${hl("val")} parameter""" + def explain = "" } - 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 = "" + class ValueClassParameterMayNotBeCallByName(valueClass: Symbol, param: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ValueClassParameterMayNotBeCallByNameID) { + def msg = s"Value class parameter `${param.name}` may not be call-by-name" + def explain = "" } - 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 = "" + class OnlyCaseClassOrCaseObjectAllowed()(implicit ctx: Context) + extends SyntaxMsg(OnlyCaseClassOrCaseObjectAllowedID) { + def msg = em"""Only ${hl("case class")} or ${hl("case object")} allowed""" + def explain = "" } - case class ExpectedToplevelDef()(implicit ctx: Context) - extends Message(ExpectedTopLevelDefID) { - val kind: String = "Syntax" - val msg: String = "Expected a toplevel definition" - val explanation: String = "" + class ExpectedToplevelDef()(implicit ctx: Context) + extends SyntaxMsg(ExpectedTopLevelDefID) { + def msg = "Expected a toplevel definition" + def explain = "" } - 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." + class SuperCallsNotAllowedInlineable(symbol: Symbol)(implicit ctx: Context) + extends SyntaxMsg(SuperCallsNotAllowedInlineableID) { + 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." } - 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 = + class NotAPath(tp: Type, usage: String)(using Context) extends TypeMsg(NotAPathID): + 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 | - a selection of an immutable path with an immutable value.""" - 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 = "" + class WrongNumberOfParameters(expected: Int)(implicit ctx: Context) + extends SyntaxMsg(WrongNumberOfParametersID) { + def msg = s"Wrong number of parameters, expected: $expected" + def explain = "" } - case class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) - extends Message(DuplicatePrivateProtectedQualifierID) { - val kind: String = "Syntax" - val msg: String = "Duplicate private/protected qualifier" - val explanation: String = + class DuplicatePrivateProtectedQualifier()(implicit ctx: Context) + extends SyntaxMsg(DuplicatePrivateProtectedQualifierID) { + 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" } - case class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) - extends Message(ExpectedStartOfTopLevelDefinitionID) { - val kind: String = "Syntax" - val msg: String = "Expected start of definition" - val explanation: String = + class ExpectedStartOfTopLevelDefinition()(implicit ctx: Context) + extends SyntaxMsg(ExpectedStartOfTopLevelDefinitionID) { + 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" } - 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 = + class NoReturnFromInlineable(owner: Symbol)(implicit ctx: Context) + extends SyntaxMsg(NoReturnFromInlineableID) { + 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. |""" } - 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 = + class ReturnOutsideMethodDefinition(owner: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ReturnOutsideMethodDefinitionID) { + 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. |""" } - 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 = + class ExtendFinalClass(clazz:Symbol, finalClazz: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ExtendFinalClassID) { + def msg = em"$clazz cannot extend ${hl("final")} $finalClazz" + def explain = 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" + class ExpectedTypeBoundOrEquals(found: Token)(implicit ctx: Context) + extends SyntaxMsg(ExpectedTypeBoundOrEqualsID) { + def msg = em"${hl("=")}, ${hl(">:")}, or ${hl("<:")} expected, but ${Tokens.showToken(found)} found" - 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. @@ -1784,20 +1659,18 @@ 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 = + class ClassAndCompanionNameClash(cls: Symbol, other: Symbol)(implicit ctx: Context) + extends NamingMsg(ClassAndCompanionNameClashID) { + 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}""" } - case class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) - extends Message(TailrecNotApplicableID) { - val kind: String = "Syntax" - val msg: String = { + class TailrecNotApplicable(symbol: Symbol)(implicit ctx: Context) + extends SyntaxMsg(TailrecNotApplicableID) { + def msg = { val reason = if (!symbol.is(Method)) em"$symbol isn't a method" else if (symbol.is(Deferred)) em"$symbol is abstract" @@ -1806,35 +1679,40 @@ object messages { s"TailRec optimisation not applicable, $reason" } - val explanation: String = "" + def explain = "" } - 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" - val msg: String = "Failure to eliminate existential type. Proceed at own risk." - val explanation: String = { + def kind: String = "Compatibility" + def msg = 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""" - } - } - - 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 = + |type used instead: $tp2 + |This choice can cause follow-on type errors or hide type errors. + |Proceed at own risk.""" + 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 + |are only approximated in a best-effort way.""" + } + + class OnlyFunctionsCanBeFollowedByUnderscore(tp: Type)(implicit ctx: Context) + extends SyntaxMsg(OnlyFunctionsCanBeFollowedByUnderscoreID) { + 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")}""" } - 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 = { + class MissingEmptyArgumentList(method: Symbol)(implicit ctx: Context) + extends SyntaxMsg(MissingEmptyArgumentListID) { + def msg = em"$method must be called with ${hl("()")} argument" + def explain = { val codeExample = """def next(): T = ... |next // is expanded to next()""" @@ -1848,33 +1726,29 @@ 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 = "" + class DuplicateNamedTypeParameter(name: Name)(implicit ctx: Context) + extends SyntaxMsg(DuplicateNamedTypeParameterID) { + def msg = em"Type parameter $name was defined multiple times." + def explain = "" } - 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 = "" + class UndefinedNamedTypeParameter(undefinedName: Name, definedNames: List[Name])(implicit ctx: Context) + extends SyntaxMsg(UndefinedNamedTypeParameterID) { + def msg = em"Type parameter $undefinedName is undefined. Expected one of ${definedNames.map(_.show).mkString(", ")}." + def explain = "" } - case class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends Message(IllegalStartOfStatementID) { - val kind: String = "Syntax" - val msg: String = { + class IllegalStartOfStatement(isModifier: Boolean)(implicit ctx: Context) extends SyntaxMsg(IllegalStartOfStatementID) { + def msg = { 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." + def explain = "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 = { + class TraitIsExpected(symbol: Symbol)(implicit ctx: Context) extends SyntaxMsg(TraitIsExpectedID) { + def msg = em"$symbol is not a trait" + def explain = { val errorCodeExample = """class A |class B @@ -1899,29 +1773,26 @@ 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 = "" + class TraitRedefinedFinalMethodFromAnyRef(method: Symbol)(implicit ctx: Context) extends SyntaxMsg(TraitRedefinedFinalMethodFromAnyRefID) { + def msg = em"Traits cannot redefine final $method from ${hl("class AnyRef")}." + def explain = "" } - case class PackageNameAlreadyDefined(pkg: Symbol)(implicit ctx: Context) extends Message(PackageNameAlreadyDefinedID) { - val (where, or) = + 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") - 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.""" - val kind: String = "Naming" - 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.""" } - 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 = + class UnapplyInvalidNumberOfArguments(qual: untpd.Tree, argTypes: List[Type])(implicit ctx: Context) + extends SyntaxMsg(UnapplyInvalidNumberOfArgumentsID) { + 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(_ => '_')}%, %) => ... @@ -1930,15 +1801,15 @@ object messages { |""".stripMargin } - 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") + class UnapplyInvalidReturnType(unapplyResult: Type, unapplyName: Symbol#ThisName)(implicit ctx: Context) + extends DeclarationMsg(UnapplyInvalidReturnTypeID) { + 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""" + 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]")}) @@ -1985,18 +1856,15 @@ object messages { """.stripMargin } - 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 = + class StaticFieldsOnlyAllowedInObjects(member: Symbol)(implicit ctx: Context) extends SyntaxMsg(StaticFieldsOnlyAllowedInObjectsID) { + 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." } - 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 = { + class StaticFieldsShouldPrecedeNonStatic(member: Symbol, defns: List[tpd.Tree])(implicit ctx: Context) extends SyntaxMsg(StaticFieldsShouldPrecedeNonStaticID) { + 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} = ... @@ -2014,10 +1882,9 @@ 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 = { + class CyclicInheritance(symbol: Symbol, addendum: => String)(implicit ctx: Context) extends SyntaxMsg(CyclicInheritanceID) { + def msg = em"Cyclic inheritance: $symbol extends itself$addendum" + def explain = { val codeExample = "class A extends A" em"""Cyclic inheritance is prohibited in Dotty. @@ -2031,10 +1898,9 @@ object messages { } } - case class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) extends Message(BadSymbolicReferenceID) { - val kind: String = "Reference" - - val msg: String = { + class BadSymbolicReference(denot: SymDenotation)(implicit ctx: Context) + extends ReferenceMsg(BadSymbolicReferenceID) { + def msg = { val denotationOwner = denot.owner val denotationName = ctx.fresh.setSetting(ctx.settings.YdebugNames, true).printer.nameString(denot.name) val file = denot.symbol.associatedFile @@ -2048,20 +1914,18 @@ object messages { |the classpath might be incompatible with the version used when compiling $src.""" } - val explanation: String = "" + def explain = "" } - 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" + class UnableToExtendSealedClass(pclazz: Symbol)(implicit ctx: Context) extends SyntaxMsg(UnableToExtendSealedClassID) { + 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" } - 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 = + class SymbolHasUnparsableVersionNumber(symbol: Symbol, migrationMessage: => String)(implicit ctx: Context) + extends SyntaxMsg(SymbolHasUnparsableVersionNumberID) { + 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 @@ -2069,25 +1933,23 @@ 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) { - val kind: String = "Syntax" - val msg: String = em"${symbol.showLocated} has changed semantics in version $migrationVersion" - val explanation: String = { + )(implicit ctx: Context) extends SyntaxMsg(SymbolChangedSemanticsInVersionID) { + 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.""" } } - 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 = { + class UnableToEmitSwitch(tooFewCases: Boolean)(implicit ctx: Context) + extends SyntaxMsg(UnableToEmitSwitchID) { + def tooFewStr: String = if (tooFewCases) " since there are not enough cases" else "" + def msg = em"Could not emit switch for ${hl("@switch")} annotated match$tooFewStr" + def explain = { val codeExample = """val ConstantB = 'B' |final val ConstantC = 'C' @@ -2112,45 +1974,41 @@ 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 = + class MissingCompanionForStatic(member: Symbol)(implicit ctx: Context) + extends SyntaxMsg(MissingCompanionForStaticID) { + 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." } - 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 = + class PolymorphicMethodMissingTypeInParent(rsym: Symbol, parentSym: Symbol)(implicit ctx: Context) + extends SyntaxMsg(PolymorphicMethodMissingTypeInParentID) { + 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.""" } - 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 = "" + class ParamsNoInline(owner: Symbol)(implicit ctx: Context) + extends SyntaxMsg(ParamsNoInlineID) { + def msg = em"""${hl("inline")} modifier can only be used for parameters of inline methods""" + def explain = "" } - case class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends Message(JavaSymbolIsNotAValueID) { - val kind: String = "Type Mismatch" - val msg: String = { + class JavaSymbolIsNotAValue(symbol: Symbol)(implicit ctx: Context) extends TypeMsg(JavaSymbolIsNotAValueID) { + def msg = { 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 = "" + def explain = "" } - case class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends Message(DoubleDefinitionID) { - val kind: String = "Duplicate Symbol" - val msg: String = { + class DoubleDefinition(decl: Symbol, previousDecl: Symbol, base: Symbol)(implicit ctx: Context) extends NamingMsg(DoubleDefinitionID) { + def msg = { def nameAnd = if (decl.name != previousDecl.name) " name and" else "" def details(implicit ctx: Context): String = if (decl.isRealMethod && previousDecl.isRealMethod) { @@ -2191,47 +2049,42 @@ object messages { |${decl.showDcl} ${symLocation(decl)} |""" + details } - val explanation: String = "" + def explain = "" } - 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 = "" + class ImportRenamedTwice(ident: untpd.Ident)(implicit ctx: Context) extends SyntaxMsg(ImportRenamedTwiceID) { + def msg = s"${ident.show} is renamed twice on the same import line." + def explain = "" } - case class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends Message(TypeTestAlwaysSucceedsID) { - val kind: String = "Syntax" - val msg: String = { + class TypeTestAlwaysSucceeds(foundCls: Symbol, testCls: Symbol)(implicit ctx: Context) extends SyntaxMsg(TypeTestAlwaysSucceedsID) { + 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 } - val explanation: String = "" + def explain = "" } // 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 = + class TermMemberNeedsResultTypeForImplicitSearch(cycleSym: Symbol)(implicit ctx: Context) + extends CyclicMsg(TermMemberNeedsNeedsResultTypeForImplicitSearchID) { + 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 } - 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 = "" + class ClassCannotExtendEnum(cls: Symbol, parent: Symbol)(implicit ctx: Context) extends SyntaxMsg(ClassCannotExtendEnumID) { + def msg = em"""$cls in ${cls.owner} extends enum ${parent.name}, but extending enums is prohibited.""" + def explain = "" } - 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 = + class NotAnExtractor(tree: untpd.Tree)(implicit ctx: Context) extends SyntaxMsg(NotAnExtractorID) { + 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]")} @@ -2242,76 +2095,66 @@ object messages { |This mechanism is used for instance in pattern ${hl("case List(x1, ..., xn)")}""".stripMargin } - 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 = "" + class MemberWithSameNameAsStatic()(implicit val ctx: Context) + extends SyntaxMsg(MemberWithSameNameAsStaticID) { + def msg = em"Companion classes cannot define members with same name as a ${hl("@static")} member" + def explain = "" } - case 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" - val msg = "A pure expression does nothing in statement position; you may be omitting necessary parentheses" - 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 } - 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 = "" + class TraitCompanionWithMutableStatic()(implicit val ctx: Context) + extends SyntaxMsg(TraitCompanionWithMutableStaticID) { + def msg = em"Companion of traits cannot define mutable @static fields" + def explain = "" } - 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 = "" + class LazyStaticField()(implicit val ctx: Context) + extends SyntaxMsg(LazyStaticFieldID) { + def msg = em"Lazy @static fields are not supported" + def explain = "" } - 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 = "" + class StaticOverridingNonStaticMembers()(implicit val ctx: Context) + extends SyntaxMsg(StaticOverridingNonStaticMembersID) { + def msg = em"${hl("@static")} members cannot override or implement non-static ones" + def explain = "" } - 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 - } + class OverloadInRefinement(rsym: Symbol)(implicit val ctx: Context) + extends DeclarationMsg(OverloadInRefinementID) { + def msg = "Refinements cannot introduce overloaded definitions" + def explain = + em"""The refinement `$rsym` introduces an overloaded definition. + |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 msg: String = + extends TypeMismatchMsg(NoMatchingOverloadID) { + def msg = em"""None of the ${err.overloadedAltsStr(alternatives)} |match ${err.expectedTypeStr(pt)}""" - val kind: String = "Type Mismatch" - val explanation: String = "" + def explain = "" } - case class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) - extends Message(StableIdentPatternID) { - override def kind: String = "Type" - override def msg: String = + class StableIdentPattern(tree: untpd.Tree, pt: Type)(implicit val ctx: Context) + extends TypeMsg(StableIdentPatternID) { + def msg = em"""Stable identifier required, but $tree found""" - override def explanation: String = "" + def explain = "" } - 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" - val msg: String = { + other: Symbol, otherTp: Type)(implicit val ctx: Context) extends DeclarationMsg(IllegalSuperAccessorID) { + 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` @@ -2360,15 +2203,14 @@ object messages { | super-call to a specific parent, e.g. $staticSuperCall |""".stripMargin } - val explanation: String = "" + def explain = "" } - case class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) - extends Message(TraitParameterUsedAsParentPrefixID) { - val kind: String = "Reference" - val msg: String = + class TraitParameterUsedAsParentPrefix(cls: Symbol)(implicit val ctx: Context) + extends DeclarationMsg(TraitParameterUsedAsParentPrefixID) { + def msg = s"${cls.show} cannot extend from a parent that is derived via its own parameters" - 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 @@ -2379,12 +2221,11 @@ object messages { |""".stripMargin } - case class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) - extends Message(UnknownNamedEnclosingClassOrObjectID) { - val kind: String = "Reference" - val msg: String = + class UnknownNamedEnclosingClassOrObject(name: TypeName)(implicit val ctx: Context) + extends ReferenceMsg(UnknownNamedEnclosingClassOrObjectID) { + def msg = em"""no enclosing class or object is named '${hl(name.show)}'""" - 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 @@ -2393,38 +2234,34 @@ object messages { """.stripMargin } - 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 = "" + class IllegalCyclicTypeReference(sym: Symbol, where: String, lastChecked: Type)(implicit val ctx: Context) + extends CyclicMsg(IllegalCyclicTypeReferenceID) { + def msg = i"illegal cyclic type reference: ${where} ${hl(lastChecked.show)} of $sym refers back to the type itself" + def explain = "" } - 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 = "" + class ErasedTypesCanOnlyBeFunctionTypes()(implicit val ctx: Context) + extends SyntaxMsg(ErasedTypesCanOnlyBeFunctionTypesID) { + def msg = "Types with erased keyword can only be function types `(erased ...) => ...`" + def explain = "" } - case class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) - extends Message(CaseClassMissingNonImplicitParamListID) { - val kind: String = "Syntax" - val msg: String = + class CaseClassMissingNonImplicitParamList(cdef: untpd.TypeDef)(implicit ctx: Context) + extends SyntaxMsg(CaseClassMissingNonImplicitParamListID) { + def msg = em"""|A ${hl("case class")} must have at least one non-implicit parameter list""" - 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 } - 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" + class EnumerationsShouldNotBeEmpty(cdef: untpd.TypeDef)(implicit ctx: Context) + extends SyntaxMsg(EnumerationsShouldNotBeEmptyID) { + def msg = "Enumerations must contain at least one case" - val explanation: String = + def explain = em"""|Enumeration ${cdef.name} must contain at least one case |Example Usage: | ${hl("enum")} ${cdef.name} { @@ -2433,12 +2270,11 @@ object messages { |""".stripMargin } - 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" + class AbstractCannotBeUsedForObjects(mdef: untpd.ModuleDef)(implicit ctx: Context) + extends SyntaxMsg(AbstractCannotBeUsedForObjectsID) { + def msg = em"${hl("abstract")} modifier cannot be used for objects" - 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: @@ -2449,24 +2285,22 @@ object messages { |""".stripMargin } - 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" + class ModifierRedundantForObjects(mdef: untpd.ModuleDef, modifier: String)(implicit ctx: Context) + extends SyntaxMsg(ModifierRedundantForObjectsID) { + def msg = em"${hl(modifier)} modifier is redundant for objects" - 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} { } |""".stripMargin } - 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" + class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) + extends SyntaxMsg(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { + def msg = i"explicit extends clause needed because both enum case and enum class have type parameters" - 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: @@ -2476,35 +2310,30 @@ object messages { |""".stripMargin } - 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" - - val explanation: String = + class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) + extends SyntaxMsg(IllegalRedefinitionOfStandardKindID) { + 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 } - 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" - - val explanation: String = + class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) + extends SyntaxMsg(NoExtensionMethodAllowedID) { + 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. |""".stripMargin } - 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" + class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) + extends SyntaxMsg(ExtensionMethodCannotHaveTypeParamsID) { + def msg = i"Extension method cannot have type parameters since some were already given previously" - val explanation: String = + def explain = em"""|Extension method: | `${mdef}` |has type parameters `[${mdef.tparams.map(_.show).mkString(",")}]`, while the extension clause has @@ -2512,23 +2341,19 @@ object messages { |""".stripMargin } - 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" - - val explanation: String = + class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) + extends SyntaxMsg(ExtensionCanOnlyHaveDefsID) { + 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 } - 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("`_`")}" - - val explanation: String = + class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) + extends SyntaxMsg(UnexpectedPatternForSummonFromID) { + 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("`_`")}. | @@ -2544,33 +2369,27 @@ object messages { |""".stripMargin } - 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" - - val explanation: String = + class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) + extends SyntaxMsg(AnonymousInstanceCannotBeEmptyID) { + 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 } - 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." - - val explanation: String = + class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) + extends SyntaxMsg(TypeSpliceInValPatternID) { + 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 } - 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" - - val explanation: String = "" + class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) + extends SyntaxMsg(ModifierNotAllowedForDefinitionID) { + def msg = s"Modifier `${flag.flagsString}` is not allowed for this definition" + def explain = "" } } 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 29c0b6a8398d..86e9996f7401 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.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/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 bf59407708a8..f3035ee5c249 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} -import reporting.trace +import reporting.messages.{UnexpectedPatternForSummonFrom, NotFoundMsg, 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} @@ -270,10 +269,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 @@ -349,7 +348,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) @@ -638,9 +637,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 +704,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 } @@ -1067,12 +1066,9 @@ trait Applications extends Compatibility { */ def saysNotFound(state: TyperState, memberName: Name)(using Context): Boolean = 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 dia :: Nil => + dia.msg match + case msg: NotFoundMsg => memberName.isEmpty || msg.name == memberName case _ => false case _ => false 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 86b4f862acfc..02cf69941ab7 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -9,23 +9,23 @@ 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 { 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) } @@ -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/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 67b568ab6033..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.messages.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 c5a476df1328..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" @@ -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( @@ -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..426f1487dcf8 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 @@ -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/src/dotty/tools/dotc/util/Signatures.scala b/compiler/src/dotty/tools/dotc/util/Signatures.scala index d59080437627..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._ @@ -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" diff --git a/compiler/src/dotty/tools/repl/ParseResult.scala b/compiler/src/dotty/tools/repl/ParseResult.scala index e81370fd894f..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.MessageContainer +import dotc.reporting.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/ReplCompiler.scala b/compiler/src/dotty/tools/repl/ReplCompiler.scala index b88957844718..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.messages +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._ @@ -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/src/dotty/tools/repl/ReplDriver.scala b/compiler/src/dotty/tools/repl/ReplDriver.scala index 042baa713fc1..2e15177477d8 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.{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.msg, 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..032159dc910a 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 /** 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..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.MessageContainer +import reporting.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/ErrorMessagesTest.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTest.scala index 3811af6b298e..59b81ecf3a32 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 { @@ -39,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/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..dbc5861ab3d6 100644 --- a/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala +++ b/compiler/test/dotty/tools/dotc/reporting/TestMessageLaziness.scala @@ -5,24 +5,21 @@ package reporting import org.junit.Assert._ import org.junit.Test import core.Contexts._ -import diagnostic.{ErrorMessageID, ExtendMessage, Message, MessageContainer} 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) { - throw new Error("Didn't stay lazy.") - val kind = "Test" - val msg = "Please don't blow up" - val explanation = "" + def msg = throw new Error("Didn't stay lazy.") + def explain = "" } @Test def assureLazy = diff --git a/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala b/compiler/test/dotty/tools/dotc/reporting/TestReporter.scala index 766844212f06..c935b579b234 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.messages._ +import messages._ +import Diagnostic._ 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.msg, 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.msg 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.msg.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/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 b7436cb32d34..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.MessageContainer +import dotc.reporting.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/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 e42805a55bd1..c6314d7a3cd6 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._ 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.msg + 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 } @@ -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 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 59fd5464bd61..536a08d31b96 100644 --- a/sbt-bridge/src/xsbt/DelegatingReporter.java +++ b/sbt-bridge/src/xsbt/DelegatingReporter.java @@ -14,12 +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.MessageContainer; -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.MessageContainer.*; +import static dotty.tools.dotc.reporting.Diagnostic.*; final public class DelegatingReporter extends AbstractReporter { private final xsbti.Reporter delegate; @@ -58,9 +57,9 @@ public void printSummary(Context ctx) { delegate.printSummary(); } - public void doReport(MessageContainer 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; @@ -71,12 +70,12 @@ public void doReport(MessageContainer 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() { @@ -124,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 MessageContainer.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)); } 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/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 diff --git a/tests/run-custom-args/tasty-interpreter/Test.scala b/tests/run-custom-args/tasty-interpreter/Test.scala index 7feff7c01300..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.MessageContainer +import dotty.tools.dotc.reporting.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)) diff --git a/tests/run-staging/i7142.scala b/tests/run-staging/i7142.scala index ba30d3e0832c..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.diagnostic.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) } }