Skip to content

Commit

Permalink
Use migration category for various warnings
Browse files Browse the repository at this point in the history
  • Loading branch information
som-snytt committed Jun 22, 2023
1 parent 0842f23 commit 88537a6
Show file tree
Hide file tree
Showing 15 changed files with 251 additions and 73 deletions.
2 changes: 2 additions & 0 deletions src/compiler/scala/tools/nsc/Global.scala
Expand Up @@ -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._
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/compiler/scala/tools/nsc/Reporting.scala
Expand Up @@ -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)
Expand Down
64 changes: 35 additions & 29 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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))
}
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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`"))
}
Expand Down Expand Up @@ -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("_$$")
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 {
Expand All @@ -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()
Expand Down Expand Up @@ -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]
Expand All @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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)
Expand Down Expand Up @@ -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.
Expand Down
40 changes: 21 additions & 19 deletions src/compiler/scala/tools/nsc/ast/parser/Scanners.scala
Expand Up @@ -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

Expand Down Expand Up @@ -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()
Expand Down
Expand Up @@ -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
Expand Down
12 changes: 9 additions & 3 deletions src/compiler/scala/tools/nsc/typechecker/Namers.scala
Expand Up @@ -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
}
Expand Down
14 changes: 6 additions & 8 deletions src/compiler/scala/tools/nsc/typechecker/NamesDefaults.scala
Expand Up @@ -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) =
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/typechecker/RefChecks.scala
Expand Up @@ -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")
}
}
Expand Down

0 comments on commit 88537a6

Please sign in to comment.