diff --git a/compiler/src/dotty/tools/dotc/core/Decorators.scala b/compiler/src/dotty/tools/dotc/core/Decorators.scala index 59440d1cb965..d392a4e3079a 100644 --- a/compiler/src/dotty/tools/dotc/core/Decorators.scala +++ b/compiler/src/dotty/tools/dotc/core/Decorators.scala @@ -9,6 +9,7 @@ import scala.util.control.NonFatal import Contexts._, Names._, Phases._, Symbols._ import printing.{ Printer, Showable }, printing.Formatting._, printing.Texts._ import transform.MegaPhase +import reporting.{Message, NoExplanation} /** This object provides useful implicit decorators for types defined elsewhere */ object Decorators { @@ -57,6 +58,9 @@ object Decorators { padding + s.replace("\n", "\n" + padding) end extension + extension (str: => String) + def toMessage: Message = reporting.NoExplanation(str) + /** Implements a findSymbol method on iterators of Symbols that * works like find but avoids Option, replacing None with NoSymbol. */ diff --git a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala index 5816e1254873..a3b594eb0f09 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErrors.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErrors.scala @@ -18,13 +18,14 @@ class TypeError(msg: String) extends Exception(msg) { def this() = this("") final def toMessage(using Context): Message = withMode(Mode.Printing)(produceMessage) - def produceMessage(using Context): Message = super.getMessage.nn + def produceMessage(using Context): Message = super.getMessage.nn.toMessage override def getMessage: String = super.getMessage.nn } class MalformedType(pre: Type, denot: Denotation, absMembers: Set[Name]) extends TypeError { override def produceMessage(using Context): Message = i"malformed type: $pre is not a legal prefix for $denot because it contains abstract type member${if (absMembers.size == 1) "" else "s"} ${absMembers.mkString(", ")}" + .toMessage } class MissingType(pre: Type, name: Name) extends TypeError { @@ -38,6 +39,7 @@ class MissingType(pre: Type, name: Name) extends TypeError { if (ctx.debug) printStackTrace() i"""cannot resolve reference to type $pre.$name |the classfile defining the type might be missing from the classpath${otherReason(pre)}""" + .toMessage } } diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index 605310989384..dc1f02c8a0fd 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -5296,16 +5296,18 @@ object Types { val et = new PreviousErrorType ctx.base.errorTypeMsg(et) = m et + def apply(s: => String)(using Context): ErrorType = + apply(s.toMessage) end ErrorType class PreviousErrorType extends ErrorType: def msg(using Context): Message = ctx.base.errorTypeMsg.get(this) match case Some(m) => m - case None => "error message from previous run no longer available" + case None => "error message from previous run no longer available".toMessage object UnspecifiedErrorType extends ErrorType { - override def msg(using Context): Message = "unspecified error" + override def msg(using Context): Message = "unspecified error".toMessage } /* Type used to track Select nodes that could not resolve a member and their qualifier is a scala.Dynamic. */ diff --git a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala index 333cd9fa9ec3..b5f95bb8b19c 100644 --- a/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala +++ b/compiler/src/dotty/tools/dotc/core/unpickleScala2/Scala2Unpickler.scala @@ -20,6 +20,7 @@ import printing.Texts._ import printing.Printer import io.AbstractFile import util.common._ +import util.NoSourcePosition import typer.Checking.checkNonCyclic import typer.Nullables._ import transform.SymUtils._ @@ -744,7 +745,7 @@ class Scala2Unpickler(bytes: Array[Byte], classRoot: ClassDenotation, moduleClas val anyTypes = boundSyms map (_ => defn.AnyType) val boundBounds = boundSyms map (_.info.bounds.hi) val tp2 = tp1.subst(boundSyms, boundBounds).subst(boundSyms, anyTypes) - report.warning(FailureToEliminateExistential(tp, tp1, tp2, boundSyms, classRoot.symbol)) + report.warning(FailureToEliminateExistential(tp, tp1, tp2, boundSyms, classRoot.symbol), NoSourcePosition) tp2 } else tp1 diff --git a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala index d1a88406fe45..8be23b932e98 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inlines.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inlines.scala @@ -155,7 +155,7 @@ object Inlines: tree, i"""|Maximal number of $reason (${setting.value}) exceeded, |Maybe this is caused by a recursive inline method? - |You can use ${setting.name} to change the limit.""", + |You can use ${setting.name} to change the limit.""".toMessage, (tree :: enclosingInlineds).last.srcPos ) if ctx.base.stopInlining && enclosingInlineds.isEmpty then diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 309dd8a20aba..ab8f578b9ac4 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -142,7 +142,12 @@ object Parsers { val length = if offset == in.offset && in.name != null then in.name.show.length else 0 syntaxError(msg, Span(offset, offset + length)) lastErrorOffset = in.offset - end if + + def syntaxError(msg: => String, offset: Int): Unit = + syntaxError(msg.toMessage, offset) + + def syntaxError(msg: => String): Unit = + syntaxError(msg, in.offset) /** Unconditionally issue an error at given span, without * updating lastErrorOffset. @@ -150,6 +155,9 @@ object Parsers { def syntaxError(msg: Message, span: Span): Unit = report.error(msg, source.atSpan(span)) + def syntaxError(msg: => String, span: Span): Unit = + syntaxError(msg.toMessage, span) + def unimplementedExpr(using Context): Select = Select(Select(rootDot(nme.scala), nme.Predef), nme.???) } @@ -259,9 +267,6 @@ object Parsers { in.skip() lastErrorOffset = in.offset - def warning(msg: Message, sourcePos: SourcePosition): Unit = - report.warning(msg, sourcePos) - def warning(msg: Message, offset: Int = in.offset): Unit = report.warning(msg, source.atSpan(Span(offset))) @@ -283,6 +288,9 @@ object Parsers { syntaxError(msg, offset) skip() + def syntaxErrorOrIncomplete(msg: => String): Unit = + syntaxErrorOrIncomplete(msg.toMessage, in.offset) + def syntaxErrorOrIncomplete(msg: Message, span: Span): Unit = if in.token == EOF then incompleteInputError(msg) @@ -350,7 +358,7 @@ object Parsers { val statFollows = mustStartStatTokens.contains(found) syntaxError( if noPrevStat then IllegalStartOfStatement(what, isModifier, statFollows) - else i"end of $what expected but ${showToken(found)} found") + else i"end of $what expected but ${showToken(found)} found".toMessage) if mustStartStatTokens.contains(found) then false // it's a statement that might be legal in an outer context else @@ -610,11 +618,11 @@ object Parsers { if in.isNewLine && !(nextIndentWidth < startIndentWidth) then warning( if startIndentWidth <= nextIndentWidth then - i"""Line is indented too far to the right, or a `{` is missing before: + i"""Line is indented too far to the right, or a `{` is missing before: | - |${t.tryToShow}""" + |${t.tryToShow}""".toMessage else - in.spaceTabMismatchMsg(startIndentWidth, nextIndentWidth), + in.spaceTabMismatchMsg(startIndentWidth, nextIndentWidth).toMessage, in.next.offset ) t @@ -627,7 +635,7 @@ object Parsers { if in.isNewLine then val nextIndentWidth = in.indentWidth(in.next.offset) if in.currentRegion.indentWidth < nextIndentWidth then - warning(i"Line is indented too far to the right, or a `{` or `:` is missing", in.next.offset) + warning(i"Line is indented too far to the right, or a `{` or `:` is missing".toMessage, in.next.offset) /* -------- REWRITES ----------------------------------------------------------- */ @@ -1732,7 +1740,7 @@ object Parsers { Ident(tpnme.USCOREkw).withSpan(Span(start, in.lastOffset, start)) else if sourceVersion.isAtLeast(future) then - deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead") + deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead".toMessage) patch(source, Span(in.offset, in.offset + 1), "?") val start = in.skipToken() typeBounds().withSpan(Span(start, in.lastOffset, start)) @@ -2171,10 +2179,11 @@ object Parsers { else Literal(Constant(())) // finally without an expression } else { - if (handler.isEmpty) warning( - EmptyCatchAndFinallyBlock(body), - source.atSpan(Span(tryOffset, endOffset(body))) - ) + if handler.isEmpty then + report.warning( + EmptyCatchAndFinallyBlock(body), + source.atSpan(Span(tryOffset, endOffset(body))) + ) EmptyTree } ParsedTry(body, handler, finalizer) @@ -2768,7 +2777,7 @@ object Parsers { warning(i"""Misleading indentation: this expression forms part of the preceding catch case. |If this is intended, it should be indented for clarity. |Otherwise, if the handler is intended to be empty, use a multi-line catch with - |an indented case.""") + |an indented case.""".toMessage) expr() else block() }) @@ -2989,7 +2998,8 @@ object Parsers { inBrackets { if in.token == THIS then if sourceVersion.isAtLeast(future) then - deprecationWarning("The [this] qualifier will be deprecated in the future; it should be dropped.") + deprecationWarning( + "The [this] qualifier will be deprecated in the future; it should be dropped.".toMessage) in.nextToken() mods | Local else mods.withPrivateWithin(ident().toTypeName) @@ -3471,7 +3481,8 @@ object Parsers { if sourceVersion.isAtLeast(future) then deprecationWarning( em"""`= _` has been deprecated; use `= uninitialized` instead. - |`uninitialized` can be imported with `scala.compiletime.uninitialized`.""", rhsOffset) + |`uninitialized` can be imported with `scala.compiletime.uninitialized`.""".toMessage, + rhsOffset) placeholderParams = placeholderParams.tail atSpan(rhs0.span) { Ident(nme.WILDCARD) } case rhs0 => rhs0 diff --git a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala index 082112d800d9..a4eff045b4ac 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Scanners.scala @@ -112,7 +112,7 @@ object Scanners { /** signal an error where the input ended in the middle of a token */ def incompleteInputError(msg: String): Unit = { - report.incompleteInputError(msg, sourcePos()) + report.incompleteInputError(msg.toMessage, sourcePos()) token = EOF errOffset = offset } diff --git a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala index 591042961dbb..3d9f5fb7ad6d 100644 --- a/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala @@ -13,6 +13,7 @@ import Parsers._ import util.Spans._ import core._ import Constants._ +import Decorators.toMessage import util.SourceFile import Utility._ @@ -379,7 +380,7 @@ object MarkupParsers { ts(0) } }, - msg => parser.incompleteInputError(msg) + msg => parser.incompleteInputError(msg.toMessage) ) /** @see xmlPattern. resynchronizes after successful parse diff --git a/compiler/src/dotty/tools/dotc/report.scala b/compiler/src/dotty/tools/dotc/report.scala index 5addb11f1a3c..00399ecbfd0a 100644 --- a/compiler/src/dotty/tools/dotc/report.scala +++ b/compiler/src/dotty/tools/dotc/report.scala @@ -18,23 +18,35 @@ object report: if ctx.settings.verbose.value then echo(msg, pos) def echo(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit = - ctx.reporter.report(new Info(msg, pos.sourcePos)) + ctx.reporter.report(new Info(msg.toMessage, pos.sourcePos)) private def issueWarning(warning: Warning)(using Context): Unit = ctx.reporter.report(warning) - def deprecationWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit = + def deprecationWarning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new DeprecationWarning(msg, pos.sourcePos)) - def migrationWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit = + def deprecationWarning(msg: => String, pos: SrcPos)(using Context): Unit = + deprecationWarning(msg.toMessage, pos) + + def migrationWarning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new MigrationWarning(msg, pos.sourcePos)) - def uncheckedWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit = + def migrationWarning(msg: => String, pos: SrcPos)(using Context): Unit = + migrationWarning(msg.toMessage, pos) + + def uncheckedWarning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new UncheckedWarning(msg, pos.sourcePos)) - def featureWarning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit = + def uncheckedWarning(msg: => String, pos: SrcPos)(using Context): Unit = + uncheckedWarning(msg.toMessage, pos) + + def featureWarning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new FeatureWarning(msg, pos.sourcePos)) + def featureWarning(msg: => String, pos: SrcPos)(using Context): Unit = + featureWarning(msg.toMessage, pos) + def featureWarning(feature: String, featureDescription: => String, featureUseSite: Symbol, required: Boolean, pos: SrcPos)(using Context): Unit = { val req = if (required) "needs to" else "should" @@ -52,30 +64,43 @@ object report: |by adding the import clause 'import $fqname' |or by setting the compiler option -language:$feature.$explain""".stripMargin if (required) error(msg, pos) - else issueWarning(new FeatureWarning(msg, pos.sourcePos)) + else issueWarning(new FeatureWarning(msg.toMessage, pos.sourcePos)) } - def warning(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit = + def warning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new Warning(msg, addInlineds(pos))) - def error(msg: Message, pos: SrcPos = NoSourcePosition, sticky: Boolean = false)(using Context): Unit = + def warning(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit = + warning(msg.toMessage, pos) + + def error(msg: Message, pos: SrcPos)(using Context): Unit = val fullPos = addInlineds(pos) - ctx.reporter.report(if (sticky) new StickyError(msg, fullPos) else new Error(msg, fullPos)) + ctx.reporter.report(new Error(msg, fullPos)) if ctx.settings.YdebugError.value then Thread.dumpStack() + def error(msg: => String, pos: SrcPos = NoSourcePosition)(using Context): Unit = + error(msg.toMessage, pos) + def error(ex: TypeError, pos: SrcPos)(using Context): Unit = - error(ex.toMessage, pos, sticky = true) - if ctx.settings.YdebugTypeError.value then ex.printStackTrace() + val fullPos = addInlineds(pos) + ctx.reporter.report(new StickyError(ex.toMessage, fullPos)) + if ctx.settings.YdebugError.value then Thread.dumpStack() - def errorOrMigrationWarning(msg: Message, pos: SrcPos = NoSourcePosition, from: SourceVersion)(using Context): Unit = + def errorOrMigrationWarning(msg: Message, pos: SrcPos, from: SourceVersion)(using Context): Unit = if sourceVersion.isAtLeast(from) then if sourceVersion.isMigrating && sourceVersion.ordinal <= from.ordinal then migrationWarning(msg, pos) else error(msg, pos) - def gradualErrorOrMigrationWarning(msg: Message, pos: SrcPos = NoSourcePosition, warnFrom: SourceVersion, errorFrom: SourceVersion)(using Context): Unit = + def errorOrMigrationWarning(msg: => String, pos: SrcPos, from: SourceVersion)(using Context): Unit = + errorOrMigrationWarning(msg.toMessage, pos, from) + + def gradualErrorOrMigrationWarning(msg: Message, pos: SrcPos, warnFrom: SourceVersion, errorFrom: SourceVersion)(using Context): Unit = if sourceVersion.isAtLeast(errorFrom) then errorOrMigrationWarning(msg, pos, errorFrom) else if sourceVersion.isAtLeast(warnFrom) then warning(msg, pos) + def gradualErrorOrMigrationWarning(msg: => String, pos: SrcPos, warnFrom: SourceVersion, errorFrom: SourceVersion)(using Context): Unit = + gradualErrorOrMigrationWarning(msg.toMessage, pos, warnFrom, errorFrom) + def restrictionError(msg: Message, pos: SrcPos = NoSourcePosition)(using Context): Unit = error(msg.mapMsg("Implementation restriction: " + _), pos) diff --git a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index dec13a4f5925..a92da7821fab 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -11,6 +11,7 @@ import dotty.tools.dotc.util.SourcePosition import java.util.Optional import scala.util.chaining._ +import core.Decorators.toMessage object Diagnostic: @@ -23,7 +24,8 @@ object Diagnostic: class Error( msg: Message, pos: SourcePosition - ) extends Diagnostic(msg, pos, ERROR) + ) extends Diagnostic(msg, pos, ERROR): + def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos) /** A sticky error is an error that should not be hidden by backtracking and * trying some alternative path. Typically, errors issued after catching @@ -46,7 +48,8 @@ object Diagnostic: class Info( msg: Message, pos: SourcePosition - ) extends Diagnostic(msg, pos, INFO) + ) extends Diagnostic(msg, pos, INFO): + def this(str: => String, pos: SourcePosition) = this(str.toMessage, pos) abstract class ConditionalWarning( msg: Message, diff --git a/compiler/src/dotty/tools/dotc/reporting/Message.scala b/compiler/src/dotty/tools/dotc/reporting/Message.scala index 77e1336a990c..9e397d606491 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Message.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Message.scala @@ -13,12 +13,6 @@ 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) - def rewriteNotice(what: String, version: SourceVersion | Null = null, options: String = "")(using Context): String = if !ctx.mode.is(Mode.Interactive) then val sourceStr = if version != null then i"-source $version" else "" diff --git a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala index 0d5acaef4960..497e77ae4a7c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Reporter.scala @@ -14,6 +14,7 @@ import dotty.tools.dotc.util.NoSourcePosition import java.io.{BufferedReader, PrintWriter} import scala.annotation.internal.sharable import scala.collection.mutable +import core.Decorators.toMessage object Reporter { /** Convert a SimpleReporter into a real Reporter */ @@ -218,7 +219,7 @@ abstract class Reporter extends interfaces.ReporterResult { for (settingName, count) <- unreportedWarnings do val were = if count == 1 then "was" else "were" val msg = s"there $were ${countString(count, settingName.tail + " warning")}; re-run with $settingName for details" - report(Warning(msg, NoSourcePosition)) + report(Warning(msg.toMessage, NoSourcePosition)) /** Print the summary of warnings and errors */ def printSummary()(using Context): Unit = { diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index d38ed1676590..15493e6805dc 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -479,7 +479,7 @@ trait Applications extends Compatibility { matchArgs(orderedArgs, methType.paramInfos, 0) case _ => if (methType.isError) ok = false - else fail(s"$methString does not take parameters") + else fail(s"$methString does not take parameters".toMessage) } /** The application was successful */ @@ -522,7 +522,7 @@ trait Applications extends Compatibility { s"parameter $aname of $methString is already instantiated" else s"$methString does not have a parameter $aname" - fail(msg, arg.asInstanceOf[Arg]) + fail(msg.toMessage, arg.asInstanceOf[Arg]) arg :: handleNamed(pnamesRest, args1, nameToArg, toDrop) } case arg :: args1 => @@ -564,7 +564,7 @@ trait Applications extends Compatibility { i"it is not the only argument to be passed to the corresponding repeated parameter $formal" else i"the corresponding parameter has type $formal which is not a repeated parameter type" - fail(em"Sequence argument type annotation `*` cannot be used here:\n$addendum", arg) + fail(em"Sequence argument type annotation `*` cannot be used here:\n$addendum".toMessage, arg) /** Add result of typing argument `arg` against parameter type `formal`. * @return The remaining formal parameter types. If the method is parameter-dependent @@ -651,7 +651,7 @@ trait Applications extends Compatibility { i"can't supply unit value with infix notation because nullary $methString takes no arguments; use dotted invocation instead: (...).${methRef.name}()" case _ => i"too many arguments for $methString" - fail(msg, arg) + fail(msg.toMessage, arg) case nil => } } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 27d02f4cc0bf..c53213d7bd37 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -472,9 +472,10 @@ object Checking { if (sym.isOneOf(flag)) fail(AbstractMemberMayNotHaveModifier(sym, flag)) def checkNoConflict(flag1: FlagSet, flag2: FlagSet, msg: => String) = - if (sym.isAllOf(flag1 | flag2)) fail(msg) + if (sym.isAllOf(flag1 | flag2)) fail(msg.toMessage) def checkCombination(flag1: FlagSet, flag2: FlagSet) = - if sym.isAllOf(flag1 | flag2) then fail(i"illegal combination of modifiers: `${flag1.flagsString}` and `${flag2.flagsString}` for: $sym") + if sym.isAllOf(flag1 | flag2) then + fail(i"illegal combination of modifiers: `${flag1.flagsString}` and `${flag2.flagsString}` for: $sym".toMessage) def checkApplicable(flag: Flag, ok: Boolean) = if sym.is(flag, butNot = Synthetic) && !ok then fail(ModifierNotAllowedForDefinition(flag)) @@ -494,15 +495,15 @@ object Checking { } if sym.is(Transparent) then if sym.isType then - if !sym.is(Trait) then fail(em"`transparent` can only be used for traits") + if !sym.is(Trait) then fail(em"`transparent` can only be used for traits".toMessage) else - if !sym.isInlineMethod then fail(em"`transparent` can only be used for inline methods") + if !sym.isInlineMethod then fail(em"`transparent` can only be used for inline methods".toMessage) if (!sym.isClass && sym.is(Abstract)) fail(OnlyClassesCanBeAbstract(sym)) // note: this is not covered by the next test since terms can be abstract (which is a dual-mode flag) // but they can never be one of ClassOnlyFlags if !sym.isClass && sym.isOneOf(ClassOnlyFlags) then - fail(em"only classes can be ${(sym.flags & ClassOnlyFlags).flagsString}") + fail(em"only classes can be ${(sym.flags & ClassOnlyFlags).flagsString}".toMessage) if (sym.is(AbsOverride) && !sym.owner.is(Trait)) fail(AbstractOverrideOnlyInTraits(sym)) if sym.is(Trait) then @@ -519,7 +520,7 @@ object Checking { if !sym.isOneOf(Method | ModuleVal) then fail(TailrecNotApplicable(sym)) else if sym.is(Inline) then - fail("Inline methods cannot be @tailrec") + fail("Inline methods cannot be @tailrec".toMessage) if sym.hasAnnotation(defn.TargetNameAnnot) && sym.isClass && sym.isTopLevelClass then fail(TargetNameOnTopLevelClass(sym)) if (sym.hasAnnotation(defn.NativeAnnot)) { @@ -538,7 +539,7 @@ object Checking { fail(CannotExtendAnyVal(sym)) if (sym.isConstructor && !sym.isPrimaryConstructor && sym.owner.is(Trait, butNot = JavaDefined)) val addendum = if ctx.settings.Ydebug.value then s" ${sym.owner.flagsString}" else "" - fail("Traits cannot have secondary constructors" + addendum) + fail(s"Traits cannot have secondary constructors$addendum".toMessage) checkApplicable(Inline, sym.isTerm && !sym.isOneOf(Mutable | Module)) checkApplicable(Lazy, !sym.isOneOf(Method | Mutable)) if (sym.isType && !sym.isOneOf(Deferred | JavaDefined)) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index a8920274b40a..3034253adb61 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -26,6 +26,9 @@ object ErrorReporting { def errorTree(tree: untpd.Tree, msg: Message)(using Context): tpd.Tree = errorTree(tree, msg, tree.srcPos) + def errorTree(tree: untpd.Tree, msg: => String)(using Context): tpd.Tree = + errorTree(tree, msg.toMessage) + def errorTree(tree: untpd.Tree, msg: TypeError, pos: SrcPos)(using Context): tpd.Tree = tree.withType(errorType(msg, pos)) @@ -34,6 +37,9 @@ object ErrorReporting { ErrorType(msg) } + def errorType(msg: => String, pos: SrcPos)(using Context): ErrorType = + errorType(msg.toMessage, pos) + def errorType(ex: TypeError, pos: SrcPos)(using Context): ErrorType = { report.error(ex, pos) ErrorType(ex.toMessage) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 020027ea9d74..42c78dcfb32c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -447,7 +447,7 @@ object Implicits: /** An explanation of the cause of the failure as a string */ def explanation(using Context): String - def msg(using Context): Message = explanation + def msg(using Context): Message = explanation.toMessage /** If search was for an implicit conversion, a note describing the failure * in more detail - this is either empty or starts with a '\n' diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 3ca15ab976dd..1aa53d866b5e 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -464,7 +464,7 @@ object RefChecks { if (autoOverride(member) || other.owner.isAllOf(JavaInterface) && warnOnMigration( - "`override` modifier required when a Java 8 default method is re-implemented", + "`override` modifier required when a Java 8 default method is re-implemented".toMessage, member.srcPos, version = `3.0`)) member.setFlag(Override) else if (member.isType && self.memberInfo(member) =:= self.memberInfo(other)) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 48b0305de5e1..b90409e72364 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -167,7 +167,7 @@ trait TypeAssigner { case _ => false def addendum = err.selectErrorAddendum(tree, qual, qualType, importSuggestionAddendum, foundWithoutNull) val msg: Message = - if tree.name == nme.CONSTRUCTOR then ex"$qualType does not have a constructor" + if tree.name == nme.CONSTRUCTOR then ex"$qualType does not have a constructor".toMessage else NotAMember(qualType, tree.name, kind, addendum) errorType(msg, tree.srcPos) diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f97a2d183ce5..49a8d44134d2 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -283,7 +283,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer def checkUnambiguous(found: Type) = val other = recur(selectors.tail) if other.exists && found.exists && found != other then - fail(em"reference to `$name` is ambiguous; it is imported twice") + fail(em"reference to `$name` is ambiguous; it is imported twice".toMessage) found if selector.rename == termName && selector.rename != nme.WILDCARD then @@ -2665,7 +2665,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer // Package will not exist if a duplicate type has already been entered, see `tests/neg/1708.scala` errorTree(tree, if pkg.exists then PackageNameAlreadyDefined(pkg) - else i"package ${tree.pid.name} does not exist") + else i"package ${tree.pid.name} does not exist".toMessage) end typedPackageDef def typedAnnotated(tree: untpd.Annotated, pt: Type)(using Context): Tree = { diff --git a/compiler/test/dotty/tools/dotc/StringFormatterTest.scala b/compiler/test/dotty/tools/dotc/StringFormatterTest.scala index a5b5902b1f2e..e745fa515443 100644 --- a/compiler/test/dotty/tools/dotc/StringFormatterTest.scala +++ b/compiler/test/dotty/tools/dotc/StringFormatterTest.scala @@ -88,7 +88,7 @@ abstract class AbstractStringFormatterTest extends DottyTest: override def initializeCtx(fc: FreshContext) = super.initializeCtx(fc.setSetting(fc.settings.color, "never")) def Foo = newSymbol(defn.RootClass, typeName("Foo"), EmptyFlags, TypeBounds.empty).typeRef - def Err = newErrorSymbol(defn.RootClass, typeName("Err"), "") + def Err = newErrorSymbol(defn.RootClass, typeName("Err"), "".toMessage) def Big = (1 to 120).foldLeft(defn.StringType)((tp, i) => RefinedType(tp, typeName("A" * 69 + i), TypeAlias(defn.IntType))) def mkCstrd = diff --git a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala index 05f218059f02..44cf83b521f4 100644 --- a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala +++ b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala @@ -6,6 +6,7 @@ import Settings._ import org.junit.Test import org.junit.Assert._ +import core.Decorators.toMessage class ScalaSettingsTests: @@ -72,14 +73,14 @@ class ScalaSettingsTests: val proc = sets.processArguments(sumy, processAll = true, skipped = Nil) val conf = sets.Wconf.valueIn(proc.sstate) val sut = reporting.WConf.fromSettings(conf).getOrElse(???) - val msg = NoExplanation("There was a problem!") + val msg = "There was a problem!".toMessage val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition) assertEquals(Action.Silent, sut.action(depr)) val feat = new Diagnostic.FeatureWarning(msg, util.NoSourcePosition) assertEquals(Action.Error, sut.action(feat)) val warn = new Diagnostic.Warning(msg, util.NoSourcePosition) assertEquals(Action.Warning, sut.action(warn)) - val nowr = new Diagnostic.Warning(NoExplanation("This is a problem."), util.NoSourcePosition) + val nowr = new Diagnostic.Warning("This is a problem.".toMessage, util.NoSourcePosition) assertEquals(Action.Silent, sut.action(nowr)) end ScalaSettingsTests