From 88537a67a191a2782214cd29d583ba7c644b1578 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 20 Jun 2023 14:47:46 -0700 Subject: [PATCH] Use migration category for various warnings --- src/compiler/scala/tools/nsc/Global.scala | 2 + src/compiler/scala/tools/nsc/Reporting.scala | 4 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 64 ++++++++++--------- .../scala/tools/nsc/ast/parser/Scanners.scala | 40 ++++++------ .../tools/nsc/typechecker/ContextErrors.scala | 2 +- .../scala/tools/nsc/typechecker/Namers.scala | 12 +++- .../tools/nsc/typechecker/NamesDefaults.scala | 14 ++-- .../tools/nsc/typechecker/RefChecks.scala | 3 +- .../tools/nsc/typechecker/Unapplies.scala | 10 +++ .../reflect/FastStringInterpolator.scala | 35 +++++++--- test/files/neg/t12798.check | 50 +++++++++++++++ test/files/neg/t12798.scala | 61 ++++++++++++++++++ test/files/neg/t12798b.check | 7 ++ test/files/neg/t12798b.scala | 16 +++++ test/files/run/t3220-213.check | 4 +- 15 files changed, 251 insertions(+), 73 deletions(-) create mode 100644 test/files/neg/t12798.check create mode 100644 test/files/neg/t12798.scala create mode 100644 test/files/neg/t12798b.check create mode 100644 test/files/neg/t12798b.scala diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 2b0c6d11f7d2..5cbc991de3b1 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -34,6 +34,7 @@ import scala.tools.nsc.io.{AbstractFile, SourceReader} import scala.tools.nsc.plugins.Plugins import scala.tools.nsc.profile.Profiler import scala.tools.nsc.reporters.{FilteringReporter, MakeFilteringForwardingReporter, Reporter} +import scala.tools.nsc.settings.NoScalaVersion import scala.tools.nsc.symtab.classfile.Pickler import scala.tools.nsc.symtab.{Flags, SymbolTable, SymbolTrackers} import scala.tools.nsc.transform._ @@ -1183,6 +1184,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter) @nowarn("cat=deprecation") val isScala3: Boolean = settings.isScala3.value val isScala3ImplicitResolution: Boolean = settings.Yscala3ImplicitResolution.value + val isScala3Migration = settings.Xmigration.value != NoScalaVersion // used in sbt def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index eadd5e9c4d8a..6b84fdd5249a 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -353,11 +353,13 @@ object Reporting { object JavaSource extends WarningCategory; add(JavaSource) + object Migration extends WarningCategory; add(Migration) + sealed trait Other extends WarningCategory { override def summaryCategory: WarningCategory = Other } object Other extends Other { override def includes(o: WarningCategory): Boolean = o.isInstanceOf[Other] }; add(Other) object OtherShadowing extends Other; add(OtherShadowing) object OtherPureStatement extends Other; add(OtherPureStatement) - object OtherMigration extends Other; add(OtherMigration) + object OtherMigration extends Other; add(OtherMigration) // API annotation object OtherMatchAnalysis extends Other; add(OtherMatchAnalysis) object OtherDebug extends Other; add(OtherDebug) object OtherNullaryOverride extends Other; add(OtherNullaryOverride) diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index 127b75e9e665..66ae27d6898a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -32,7 +32,8 @@ import scala.tools.nsc.Reporting.WarningCategory * the beginnings of a campaign against this latest incursion by Cutty * McPastington and his army of very similar soldiers. */ -trait ParsersCommon extends ScannersCommon { self => +trait ParsersCommon extends ScannersCommon { + self => val global : Global // the use of currentUnit in the parser should be avoided as it might // cause unexpected behaviour when you work with two units at the @@ -606,6 +607,22 @@ self => and } + // warn under -Xsource:3, either deprecation or migration under -Xmigration + def migrationWarning(offset: Offset, msg: String, since: String): Unit = + if (currentRun.isScala3) + if (currentRun.isScala3Migration) warning(offset, msg, WarningCategory.Migration) + else deprecationWarning(offset, msg, since) + + // deprecation or migration under -Xsource:3 + def hardMigrationWarning(offset: Offset, msg: String, since: String): Unit = + if (currentRun.isScala3) migrationWarning(offset, msg, since) + else deprecationWarning(offset, msg, since) + + // deprecation or migration under -Xsource:3, with different messages + def hardMigrationWarning(offset: Offset, depr: => String, migr: => String, since: String): Unit = + if (currentRun.isScala3) migrationWarning(offset, migr, since) + else deprecationWarning(offset, depr, since) + def expectedMsgTemplate(exp: String, fnd: String) = s"$exp expected but $fnd found." def expectedMsg(token: Token): String = in.token match { @@ -782,8 +799,7 @@ self => val msg = "parentheses are required around the parameter of a lambda" val wrn = sm"""|$msg |Use '-Wconf:msg=lambda-parens:s' to silence this warning.""" - if (currentRun.isScala3) - deprecationWarning(tree.pos.point, wrn, "2.13.11") + migrationWarning(tree.pos.point, wrn, "2.13.11") List(convertToParam(tree)) case _ => List(convertToParam(tree)) } @@ -994,10 +1010,7 @@ self => def finishBinaryOp(isExpr: Boolean, opinfo: OpInfo, rhs: Tree): Tree = { import opinfo._ if (targs.nonEmpty) - if (currentRun.isScala3) - syntaxError(offset, "type application is not allowed for infix operators") - else - deprecationWarning(offset, "type application will be disallowed for infix operators", "2.13.11") + migrationWarning(offset, "type application is not allowed for infix operators", "2.13.11") val operatorPos: Position = Position.range(rhs.pos.source, offset, offset, offset + operator.length) val pos = lhs.pos.union(rhs.pos).union(operatorPos).withEnd(in.lastOffset).withPoint(offset) @@ -2064,8 +2077,7 @@ self => def msg(what: String, instead: String): String = s"`val` keyword in for comprehension is $what: $instead" if (hasEq) { val without = "instead, bind the value without `val`" - if (currentRun.isScala3) syntaxError(in.offset, msg("unsupported", without)) - else deprecationWarning(in.offset, msg("deprecated", without), "2.10.0") + hardMigrationWarning(in.offset, msg("deprecated", without), msg("unsupported", without), "2.10.0") } else syntaxError(in.offset, msg("unsupported", "just remove `val`")) } @@ -2616,9 +2628,9 @@ self => checkQMarkDefinition() checkKeywordDefinition() val pname: TypeName = - if (in.token == USCORE && (isAbstractOwner || !currentRun.isScala3)) { + if (in.token == USCORE) { if (!isAbstractOwner) - deprecationWarning(in.offset, "Top-level wildcard is not allowed and will error under -Xsource:3", "2.13.7") + hardMigrationWarning(in.offset, "Top-level wildcard is not allowed", "2.13.7") in.nextToken() freshTypeName("_$$") } @@ -2631,8 +2643,7 @@ self => def msg(what: String) = s"""view bounds are $what; use an implicit parameter instead. | example: instead of `def f[A <% Int](a: A)` use `def f[A](a: A)(implicit ev: A => Int)`""".stripMargin while (in.token == VIEWBOUND) { - if (currentRun.isScala3) syntaxError(in.offset, msg("unsupported")) - else deprecationWarning(in.offset, msg("deprecated"), "2.12.0") + hardMigrationWarning(in.offset, msg("deprecated"), msg("unsupported"), "2.12.0") contextBoundBuf += atPos(in.skipToken())(makeFunctionTypeTree(List(Ident(pname)), typ())) } while (in.token == COLON) { @@ -2932,12 +2943,12 @@ self => def funDefOrDcl(start : Int, mods: Modifiers): Tree = { in.nextToken() if (in.token == THIS) { - def missingEquals() = deprecationWarning(in.lastOffset, "procedure syntax is deprecated for constructors: add `=`, as in method definition", "2.13.2") + def missingEquals() = hardMigrationWarning(in.lastOffset, "procedure syntax is deprecated for constructors: add `=`, as in method definition", "2.13.2") atPos(start, in.skipToken()) { val vparamss = paramClauses(nme.CONSTRUCTOR, classContextBounds map (_.duplicate), ofCaseClass = false) newLineOptWhenFollowedBy(LBRACE) val rhs = - if (in.token == LBRACE && !currentRun.isScala3) { + if (in.token == LBRACE) { missingEquals(); atPos(in.offset) { constrBlock(vparamss) } } else { @@ -2970,15 +2981,13 @@ self => val rhs = if (isStatSep || in.token == RBRACE) { if (restype.isEmpty) { - if (currentRun.isScala3) syntaxError(in.lastOffset, msg("unsupported", ": Unit")) - else deprecationWarning(in.lastOffset, msg("deprecated", ": Unit"), "2.13.0") + hardMigrationWarning(in.lastOffset, msg("deprecated", ": Unit"), msg("unsupported", ": Unit"), "2.13.0") restype = scalaUnitConstr } newmods |= Flags.DEFERRED EmptyTree } else if (restype.isEmpty && in.token == LBRACE) { - if (currentRun.isScala3) syntaxError(in.offset, msg("unsupported", ": Unit =")) - else deprecationWarning(in.offset, msg("deprecated", ": Unit ="), "2.13.0") + hardMigrationWarning(in.offset, msg("deprecated", ": Unit ="), msg("unsupported", ": Unit ="), "2.13.0") restype = scalaUnitConstr blockExpr() } else { @@ -2996,9 +3005,7 @@ self => if (nme.isEncodedUnary(name) && vparamss.nonEmpty) { def instead = DefDef(newmods, name.toTermName.decodedName, tparams, vparamss.drop(1), restype, rhs) def unaryMsg(what: String) = s"unary prefix operator definition with empty parameter list is $what: instead, remove () to declare as `$instead`" - def warnNilary(): Unit = - if (currentRun.isScala3) syntaxError(nameOffset, unaryMsg("unsupported")) - else deprecationWarning(nameOffset, unaryMsg("deprecated"), "2.13.4") + def warnNilary() = hardMigrationWarning(nameOffset, unaryMsg("deprecated"), unaryMsg("unsupported"), "2.13.4") vparamss match { case List(List()) => warnNilary() case List(List(), x :: xs) if x.mods.isImplicit => warnNilary() @@ -3127,7 +3134,7 @@ self => val nameOffset = in.offset val name = identForType() if (currentRun.isScala3 && in.token == LBRACKET && isAfterLineEnd) - deprecationWarning(in.offset, "type parameters should not follow newline", "2.13.7") + migrationWarning(in.offset, "type parameters should not follow newline", "2.13.7") atPos(start, if (name == tpnme.ERROR) start else nameOffset) { savingClassContextBounds { val contextBoundBuf = new ListBuffer[Tree] @@ -3136,7 +3143,7 @@ self => val tstart = (in.offset :: classContextBounds.map(_.pos.start)).min if (!classContextBounds.isEmpty && mods.isTrait) { val viewBoundsExist = if (currentRun.isScala3) "" else " nor view bounds `<% ...`" - syntaxError(s"traits cannot have type parameters with context bounds `: ...`$viewBoundsExist", skipIt = false) + syntaxError(s"traits cannot have type parameters with context bounds `: ...`$viewBoundsExist", skipIt = false) classContextBounds = List() } val constrAnnots = if (!mods.isTrait) constructorAnnotations() else Nil @@ -3232,7 +3239,7 @@ self => val advice = if (currentRun.isScala3) "use trait parameters instead." else "they will be replaced by trait parameters in 3.0, see the migration guide on avoiding var/val in traits." - deprecationWarning(braceOffset, s"early initializers are deprecated; $advice", "2.13.0") + hardMigrationWarning(braceOffset, s"early initializers are deprecated; $advice", "2.13.0") val earlyDefs: List[Tree] = body.map(ensureEarlyDef).filter(_.nonEmpty) in.nextToken() val parents = templateParents() @@ -3253,8 +3260,7 @@ self => copyValDef(vdef)(mods = mods | Flags.PRESUPER) case tdef @ TypeDef(mods, name, tparams, rhs) => def msg(what: String): String = s"early type members are $what: move them to the regular body; the semantics are the same" - if (currentRun.isScala3) syntaxError(tdef.pos.point, msg("unsupported")) - else deprecationWarning(tdef.pos.point, msg("deprecated"), "2.11.0") + hardMigrationWarning(tdef.pos.point, msg("deprecated"), msg("unsupported"), "2.11.0") treeCopy.TypeDef(tdef, mods | Flags.PRESUPER, name, tparams, rhs) case docdef @ DocDef(comm, rhs) => treeCopy.DocDef(docdef, comm, rhs) @@ -3296,8 +3302,8 @@ self => // warn now if user wrote parents for package object; `gen.mkParents` adds AnyRef to parents if (currentRun.isScala3 && name == nme.PACKAGEkw && !parents.isEmpty) - deprecationWarning(tstart, """package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); - |drop the `extends` clause or use a regular object instead""".stripMargin, "3.0.0") + migrationWarning(tstart, sm"""|package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); + |drop the `extends` clause or use a regular object instead""", "3.0.0") atPos(templateOffset) { // Exclude only the 9 primitives plus AnyVal. diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 8d2286b525e5..0c601a03200f 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -13,19 +13,17 @@ package scala.tools.nsc package ast.parser +import scala.annotation.{switch, tailrec} +import scala.collection.mutable, mutable.{ArrayBuffer, ListBuffer} +import scala.reflect.internal.Chars._ +import scala.reflect.internal.util._ +import scala.tools.nsc.Reporting.WarningCategory +import scala.tools.nsc.ast.parser.xml.Utility.isNameStart import scala.tools.nsc.settings.ScalaVersion import scala.tools.nsc.util.{CharArrayReader, CharArrayReaderData} -import scala.reflect.internal.util._ -import scala.reflect.internal.Chars._ import Tokens._ -import scala.annotation.{switch, tailrec} -import scala.collection.mutable -import mutable.{ArrayBuffer, ListBuffer} -import scala.tools.nsc.ast.parser.xml.Utility.isNameStart import java.lang.StringBuilder -import scala.tools.nsc.Reporting.WarningCategory - object Cbuf { final val TargetCapacity = 256 @@ -958,27 +956,31 @@ trait Scanners extends ScannersCommon { } private def replaceUnicodeEscapesInTriple(): Unit = - if(strVal != null) { + if (strVal != null) try { - val replaced = StringContext.processUnicode(strVal) - if(replaced != strVal) { - val diffPosition = replaced.zip(strVal).zipWithIndex.collectFirst{ case ((r, o), i) if r != o => i}.getOrElse(replaced.length - 1) - deprecationWarning(offset + 3 + diffPosition, "Unicode escapes in triple quoted strings are deprecated, use the literal character instead", since="2.13.2") + val processed = StringContext.processUnicode(strVal) + if (processed != strVal) { + val diffPosition = processed.zip(strVal).zipWithIndex.collectFirst{ case ((r, o), i) if r != o => i}.getOrElse(processed.length - 1) + val pos = offset + 3 + diffPosition + def msg(what: String) = s"Unicode escapes in triple quoted strings are $what. Use the literal character instead." + if (!currentRun.isScala3) { + deprecationWarning(pos, msg("deprecated"), since="2.13.2") + strVal = processed + } + else warning(pos, msg("ignored under -Xsource:3"), WarningCategory.Migration) } - strVal = replaced } catch { - case ue: StringContext.InvalidUnicodeEscapeException => { - syntaxError(offset + 3 + ue.index, ue.getMessage()) - } + case ue: StringContext.InvalidUnicodeEscapeException => + if (!currentRun.isScala3) + syntaxError(offset + 3 + ue.index, ue.getMessage()) } - } @tailrec private def getRawStringLit(): Unit = { if (ch == '\"') { nextRawChar() if (isTripleQuote()) { setStrVal() - if (!currentRun.isScala3) replaceUnicodeEscapesInTriple() + replaceUnicodeEscapesInTriple() token = STRINGLIT } else getRawStringLit() diff --git a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala index 800fef31e99d..1675281f730f 100644 --- a/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala +++ b/src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala @@ -190,7 +190,7 @@ trait ContextErrors extends splain.SplainErrors { s"Implicit definition ${if (currentRun.isScala3) "must" else "should"} have explicit type${ if (!inferred.isErroneous) s" (inferred $inferred)" else "" }" - if (currentRun.isScala3) ErrorUtils.issueNormalTypeError(tree, msg)(cx) + if (currentRun.isScala3 && currentRun.isScala3Migration) cx.warning(tree.pos, msg, WarningCategory.Migration) else cx.warning(tree.pos, msg, WarningCategory.OtherImplicitType) } val sym = tree.symbol diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 6323357a5c5b..3864c990f021 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1148,9 +1148,15 @@ trait Namers extends MethodSynthesis { case _ => true } } - if (inferOverridden) pt - else dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt)) - .tap(InferredImplicitError(tree, _, context)) + val legacy = dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt)) + .tap(InferredImplicitError(tree, _, context)) + if (inferOverridden) { + val prev = legacy + if (!(prev =:= pt) && currentRun.isScala3Migration) + runReporting.warning(tree.pos, s"under -Xsource:3, inferred $pt instead of $prev", WarningCategory.Migration, tree.symbol) + pt + } + else legacy }.setPos(tree.pos.focus) tree.tpt.tpe } diff --git a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala index 941a36f318f0..e06c50b3e424 100644 --- a/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala +++ b/src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala @@ -524,7 +524,7 @@ trait NamesDefaults { self: Analyzer => * Verifies that names are not specified twice, and positional args don't appear after named ones. */ def removeNames(typer: Typer)(args: List[Tree], params: List[Symbol]): (List[Tree], Array[Int]) = { - implicit val context0 = typer.context + implicit val context0: Context = typer.context def matchesName(param: Symbol, name: Name, argIndex: Int) = { def warn(msg: String, since: String) = context0.deprecationWarning(args(argIndex).pos, param, msg, since) def checkDeprecation(anonOK: Boolean) = @@ -554,7 +554,7 @@ trait NamesDefaults { self: Analyzer => val NamedArg(Ident(name), rhs) = arg: @unchecked params.indexWhere(p => matchesName(p, name, argIndex)) match { case -1 => - val warnVariableInScope = !currentRun.isScala3 && context0.lookupSymbol(name, _.isVariable).isSuccess + val warnVariableInScope = (!currentRun.isScala3 || currentRun.isScala3Migration) && context0.lookupSymbol(name, _.isVariable).isSuccess UnknownParameterNameNamesDefaultError(arg, name, warnVariableInScope) case paramPos if argPos contains paramPos => val existingArgIndex = argPos.indexWhere(_ == paramPos) @@ -574,12 +574,10 @@ trait NamesDefaults { self: Analyzer => val t = stripNamedArg(arg, argIndex) if (!t.isErroneous && argPos(argIndex) < 0) argPos(argIndex) = argIndex t - case (arg, argIndex) => - if (positionalAllowed) { - argPos(argIndex) = argIndex - arg - } else - PositionalAfterNamedNamesDefaultError(arg) + case (arg, argIndex) if positionalAllowed => + argPos(argIndex) = argIndex + arg + case (arg, _) => PositionalAfterNamedNamesDefaultError(arg) } } (namelessArgs, argPos) diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 8c0dd5a00225..3e598dd631e7 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -833,7 +833,8 @@ abstract class RefChecks extends Transform { .filter(c => c.exists && c.isClass) overridden foreach { sym2 => def msg(what: String) = s"shadowing a nested class of a parent is $what but $clazz shadows $sym2 defined in ${sym2.owner}; rename the class to something else" - if (currentRun.isScala3) reporter.error(clazz.pos, msg("unsupported")) + if (currentRun.isScala3 && currentRun.isScala3Migration) + runReporting.warning(clazz.pos, msg("deprecated"), WarningCategory.Migration, clazz) else runReporting.deprecationWarning(clazz.pos, clazz, currentOwner, msg("deprecated"), "2.13.2") } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index cb6356103af9..a9cbcdc02ec0 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -16,6 +16,8 @@ package typechecker import scala.annotation.tailrec import symtab.Flags._ import scala.reflect.internal.util.ListOfNil +import scala.tools.nsc.Reporting.WarningCategory +import scala.util.chaining._ /* * @author Martin Odersky @@ -154,6 +156,10 @@ trait Unapplies extends ast.TreeDSL { val mods = if (applyShouldInheritAccess(inheritedMods)) (caseMods | (inheritedMods.flags & PRIVATE)).copy(privateWithin = inheritedMods.privateWithin) + .tap { mods => + if (currentRun.isScala3Migration && mods != caseMods) + runReporting.warning(cdef.pos, "constructor modifiers are assumed by synthetic `apply` method", WarningCategory.Migration, cdef.symbol) + } else caseMods factoryMeth(mods, nme.apply, cdef) @@ -274,6 +280,10 @@ trait Unapplies extends ast.TreeDSL { if (currentRun.isScala3) { val inheritedMods = constrMods(cdef) Modifiers(SYNTHETIC | (inheritedMods.flags & AccessFlags), inheritedMods.privateWithin) + .tap { mods => + if (currentRun.isScala3Migration && mods != Modifiers(SYNTHETIC)) + runReporting.warning(cdef.pos, "constructor modifiers are assumed by synthetic `copy` method", WarningCategory.Migration, cdef.symbol) + } } else Modifiers(SYNTHETIC) val copyDefDef = atPos(cdef.pos.focus)( diff --git a/src/compiler/scala/tools/reflect/FastStringInterpolator.scala b/src/compiler/scala/tools/reflect/FastStringInterpolator.scala index f16ddabb7845..a81d7239a249 100644 --- a/src/compiler/scala/tools/reflect/FastStringInterpolator.scala +++ b/src/compiler/scala/tools/reflect/FastStringInterpolator.scala @@ -10,7 +10,10 @@ * additional information regarding copyright ownership. */ -package scala.tools.reflect +package scala.tools +package reflect + +import nsc.Reporting.WarningCategory trait FastStringInterpolator extends FormatInterpolator { import c.universe._ @@ -33,19 +36,33 @@ trait FastStringInterpolator extends FormatInterpolator { try parts.mapConserve { case lit @ Literal(Constant(stringVal: String)) => - val value = - if (isRaw && currentRun.isScala3) stringVal - else if (isRaw) { + def asRaw = { + if (currentRun.isScala3 && !currentRun.isScala3Migration) stringVal + else { val processed = StringContext.processUnicode(stringVal) if (processed != stringVal) { - val diffindex = processed.zip(stringVal).zipWithIndex.collectFirst { - case ((p, o), i) if p != o => i - }.getOrElse(processed.length - 1) + val pos = { + val diffindex = processed.zip(stringVal).zipWithIndex.collectFirst { + case ((p, o), i) if p != o => i + }.getOrElse(processed.length - 1) + lit.pos.withShift(diffindex) + } + def msg(what: String) = s"Unicode escapes in raw interpolations are $what. Use literal characters instead." - runReporting.deprecationWarning(lit.pos.withShift(diffindex), "Unicode escapes in raw interpolations are deprecated. Use literal characters instead.", "2.13.2", "", "") + if (currentRun.isScala3) { + runReporting.warning(pos, msg("ignored under -Xsource:3"), WarningCategory.Migration, c.internal.enclosingOwner) + stringVal + } + else { + runReporting.deprecationWarning(pos, msg("deprecated"), "2.13.2", "", "") + processed + } } - processed + else stringVal } + } + val value = + if (isRaw) asRaw else StringContext.processEscapes(stringVal) val k = Constant(value) // To avoid the backlash of backslash, taken literally by Literal, escapes are processed strictly (scala/bug#11196) diff --git a/test/files/neg/t12798.check b/test/files/neg/t12798.check new file mode 100644 index 000000000000..59b28d7c5aeb --- /dev/null +++ b/test/files/neg/t12798.check @@ -0,0 +1,50 @@ +t12798.scala:11: error: unknown parameter name: z +Note that assignments in argument position are no longer allowed since Scala 2.13. +To express the assignment expression, wrap it in brackets, e.g., `{ z = ... }`. + f(42, z = 27) + ^ +t12798.scala:25: error: unary prefix operator definition with empty parameter list is unsupported: instead, remove () to declare as `def unary_- = -42` + def unary_-() = -42 + ^ +t12798.scala:28: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); +drop the `extends` clause or use a regular object instead +package object tester extends Runnable { + ^ +t12798.scala:33: error: procedure syntax is deprecated for constructors: add `=`, as in method definition + def this(s: String) { this() } + ^ +t12798.scala:34: error: procedure syntax is unsupported: instead, add `: Unit =` to explicitly declare `f`'s return type + def f() { println() } + ^ +t12798.scala:35: error: procedure syntax is unsupported: instead, add `: Unit` to explicitly declare `g`'s return type + def g() + ^ +t12798.scala:39: error: parentheses are required around the parameter of a lambda +Use '-Wconf:msg=lambda-parens:s' to silence this warning. + def f = List(42).map { x: Int => x + 1 } + ^ +t12798.scala:43: error: type application is not allowed for infix operators + def f = List(42) map [Int] (_ + 1) + ^ +t12798.scala:46: error: Top-level wildcard is not allowed +class `misuse of underscore`[_] + ^ +t12798.scala:48: error: early initializers are deprecated; use trait parameters instead. +class `early bird` extends { val x = "hello, world" } with Runnable { def run() = println(x) } + ^ +t12798.scala:17: error: Unicode escapes in raw interpolations are ignored under -Xsource:3. Use literal characters instead. + def f = raw"\u0043 is for $entry" + ^ +t12798.scala:18: error: Unicode escapes in raw interpolations are ignored under -Xsource:3. Use literal characters instead. + def g = raw"""\u0043 is for Cat""" + ^ +t12798.scala:50: error: constructor modifiers are assumed by synthetic `copy` method +case class `case mods propagate` private (s: String) + ^ +t12798.scala:60: error: under -Xsource:3, inferred Option[Int] instead of Some[Int] + override def f = Some(27) + ^ +t12798.scala:52: error: constructor modifiers are assumed by synthetic `apply` method +case class `copyless case mods propagate` private (s: String) { + ^ +15 errors diff --git a/test/files/neg/t12798.scala b/test/files/neg/t12798.scala new file mode 100644 index 000000000000..c4218110de86 --- /dev/null +++ b/test/files/neg/t12798.scala @@ -0,0 +1,61 @@ +// scalac: -Wconf:cat=migration:e -Xmigration -Xsource:3 + +// Demonstrate migration warnings at typer for -Xsource:3 + +class `named arg is not assignment` { + // unfortunately, z member is not available yet while erroring in g + //var z = 17 + def f(x: Int, y: Int) = x + y + def g = { + var z = 17 + f(42, z = 27) + } +} + +class `interpolated unicode such as \u0043` { + def entry = "Cat" + def f = raw"\u0043 is for $entry" + def g = raw"""\u0043 is for Cat""" +} + +// it was always specified that unary is parameterless. +// The most correct behavior would be that you can define unary_-() +// but you can't use it as unary prefix. +class `unary op lacks parens` { + def unary_-() = -42 +} + +package object tester extends Runnable { + def run() = () +} + +abstract class `procedure syntax` { + def this(s: String) { this() } + def f() { println() } + def g() +} + +class `lambda parens` { + def f = List(42).map { x: Int => x + 1 } +} + +class `infix type args` { + def f = List(42) map [Int] (_ + 1) +} + +class `misuse of underscore`[_] + +class `early bird` extends { val x = "hello, world" } with Runnable { def run() = println(x) } + +case class `case mods propagate` private (s: String) + +case class `copyless case mods propagate` private (s: String) { + def copy(x: String) = this +} + +class Parent { + def f: Option[Int] = Some(42) +} +class Child extends Parent { + override def f = Some(27) +} diff --git a/test/files/neg/t12798b.check b/test/files/neg/t12798b.check new file mode 100644 index 000000000000..901b5bf025e7 --- /dev/null +++ b/test/files/neg/t12798b.check @@ -0,0 +1,7 @@ +t12798b.scala:9: error: shadowing a nested class of a parent is deprecated but class P shadows class P defined in class HasP; rename the class to something else + class P extends super.P + ^ +t12798b.scala:15: error: shadowing a nested class of a parent is deprecated but class Q shadows class Q defined in class HasQ; rename the class to something else + class Q + ^ +2 errors diff --git a/test/files/neg/t12798b.scala b/test/files/neg/t12798b.scala new file mode 100644 index 000000000000..3bba6fdb2274 --- /dev/null +++ b/test/files/neg/t12798b.scala @@ -0,0 +1,16 @@ +// scalac: -Wconf:cat=migration:e -Xmigration -Xsource:3 + +// Demonstrate migration warnings at refchecks for -Xsource:3 + +class HasP { + class P +} +class AnotherP extends HasP { + class P extends super.P +} +class HasQ { + class Q +} +class AnotherQ extends HasQ { + class Q +} diff --git a/test/files/run/t3220-213.check b/test/files/run/t3220-213.check index c696f055d727..489adb23033d 100644 --- a/test/files/run/t3220-213.check +++ b/test/files/run/t3220-213.check @@ -1,7 +1,7 @@ -t3220-213.scala:9: warning: Unicode escapes in triple quoted strings are deprecated, use the literal character instead +t3220-213.scala:9: warning: Unicode escapes in triple quoted strings are deprecated. Use the literal character instead. def inTripleQuoted = """\u000A""" ^ -t3220-213.scala:45: warning: Unicode escapes in triple quoted strings are deprecated, use the literal character instead +t3220-213.scala:45: warning: Unicode escapes in triple quoted strings are deprecated. Use the literal character instead. "tab unicode escape in triple quoted string" -> """tab\u0009tab""", ^ t3220-213.scala:10: warning: Unicode escapes in raw interpolations are deprecated. Use literal characters instead.