From e04f153d60102c7893f1b87638c15c79f2ecb13e Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Tue, 10 Oct 2023 12:55:11 -0700 Subject: [PATCH 1/2] Distinguish between -Xsource:3migrate and -Xsource:3cross Add documentation to `-Xsource:help`. -Xsource:3migrate is an alias for `-Xsource:3`, it enables fatal warnings but doesn't change semantics. -Xsource:3cross adpots Scala 3 semantics for certain constructs and skips the warning, for example modifiers of case class apply / copy methods. Warnings for things that should be addressed because they are deprecated / unsupported in Scala 3 remain. --- src/compiler/scala/tools/nsc/Global.scala | 4 +- src/compiler/scala/tools/nsc/Reporting.scala | 6 +- .../scala/tools/nsc/ast/parser/Parsers.scala | 4 +- .../scala/tools/nsc/ast/parser/Scanners.scala | 21 ++--- .../tools/nsc/settings/MutableSettings.scala | 13 +++- .../tools/nsc/settings/ScalaSettings.scala | 39 +++++++++- .../tools/nsc/settings/ScalaVersion.scala | 34 ++++---- .../tools/nsc/typechecker/Adaptations.scala | 11 +-- .../nsc/typechecker/AnalyzerPlugins.scala | 2 +- .../tools/nsc/typechecker/Contexts.scala | 3 +- .../scala/tools/nsc/typechecker/Namers.scala | 32 ++++---- .../scala/tools/nsc/typechecker/Typers.scala | 20 ++--- .../tools/nsc/typechecker/Unapplies.scala | 42 ++++++---- .../reflect/FastStringInterpolator.scala | 8 +- .../reflect/internal/StdAttachments.scala | 4 + .../reflect/runtime/JavaUniverseForce.scala | 2 + .../neg/caseclass_private_constructor.scala | 2 +- test/files/neg/deprecated-options.check | 2 +- test/files/neg/deprecationsFor3.check | 33 ++++++++ test/files/neg/deprecationsFor3.scala | 39 ++++++++++ test/files/neg/implicit-any2stringadd.scala | 2 +- test/files/neg/multiLineOps-b.scala | 2 +- test/files/neg/multiLineOps-c.scala | 2 +- test/files/neg/multiLineOps.scala | 2 +- test/files/neg/source3Xneg.check | 22 ++++++ test/files/neg/source3Xneg.scala | 62 +++++++++++++++ test/files/neg/source3XnegRefchecks.check | 6 ++ test/files/neg/source3XnegRefchecks.scala | 6 ++ test/files/neg/source3neg.check | 45 +++++++++++ test/files/neg/source3neg.scala | 62 +++++++++++++++ test/files/neg/t12798-migration.check | 6 +- test/files/neg/t12798.check | 6 +- test/files/neg/t5265b.check | 2 +- test/files/neg/t7212.check | 24 ++---- test/files/neg/t7212.scala | 2 +- test/files/neg/t7212b.check | 16 ++++ test/files/neg/t7212b.scala | 22 ++++++ test/files/neg/t8035-deprecated.check | 5 +- test/files/neg/t8035-deprecated.scala | 2 +- test/files/neg/t8035-removed.check | 21 +++-- test/files/neg/t8035-removed.scala | 2 +- test/files/pos/infixed.scala | 2 +- test/files/pos/leading-infix-op.scala | 2 +- test/files/pos/multiLineOps.scala | 2 +- test/files/pos/t7212.scala | 2 +- test/files/pos/t7212b/ScalaThing.scala | 2 +- test/files/run/interpolator-hygiene.scala | 31 -------- test/files/run/multiLineOps.scala | 2 +- test/files/run/productElementName.scala | 3 +- test/files/run/source3Xrun.scala | 71 +++++++++++++++++ test/files/run/source3run.scala | 78 +++++++++++++++++++ test/files/run/t12071.scala | 2 +- test/files/run/t3220-214.check | 9 --- test/files/run/t3220-214.scala | 2 +- .../tools/nsc/settings/ScalaVersionTest.scala | 15 +++- 55 files changed, 679 insertions(+), 184 deletions(-) create mode 100644 test/files/neg/deprecationsFor3.check create mode 100644 test/files/neg/deprecationsFor3.scala create mode 100644 test/files/neg/source3Xneg.check create mode 100644 test/files/neg/source3Xneg.scala create mode 100644 test/files/neg/source3XnegRefchecks.check create mode 100644 test/files/neg/source3XnegRefchecks.scala create mode 100644 test/files/neg/source3neg.check create mode 100644 test/files/neg/source3neg.scala create mode 100644 test/files/neg/t7212b.check create mode 100644 test/files/neg/t7212b.scala delete mode 100644 test/files/run/interpolator-hygiene.scala create mode 100644 test/files/run/source3Xrun.scala create mode 100644 test/files/run/source3run.scala delete mode 100644 test/files/run/t3220-214.check diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index f1348a764ddd..d186ad5c33d4 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -1182,7 +1182,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter) // We hit these checks regularly. They shouldn't change inside the same run, so cache the comparisons here. @nowarn("cat=deprecation") - val isScala3: Boolean = settings.isScala3.value + val isScala3: Boolean = settings.isScala3.value // reporting.isScala3 + @nowarn("cat=deprecation") + val isScala3Cross: Boolean = settings.isScala3Cross.value // reporting.isScala3Cross val isScala3ImplicitResolution: Boolean = settings.Yscala3ImplicitResolution.value // used in sbt diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index fb9213bc60f0..5226a1433adc 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -44,8 +44,10 @@ trait Reporting extends internal.Reporting { self: ast.Positions with Compilatio if (settings.rootdir.value.isEmpty) "" else Regex.quote(new java.io.File(settings.rootdir.value).getCanonicalPath.replace("\\", "/")) @nowarn("cat=deprecation") - def isScala3 = settings.isScala3.value - def isScala3Migration = settings.Xmigration.value != NoScalaVersion + val isScala3 = settings.isScala3.value + @nowarn("cat=deprecation") + val isScala3Cross: Boolean = settings.isScala3Cross.value + val isScala3Migration = settings.Xmigration.value != NoScalaVersion lazy val wconf = WConf.parse(settings.Wconf.value, rootDirPrefix) match { case Left(msgs) => val multiHelp = diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index e76f4a648b6d..f0938f755f49 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1556,8 +1556,8 @@ self => // Scala 2 allowed uprooted Ident for purposes of virtualization val t1 = - if (currentRun.isScala3) atPos(o2p(start)) { Select(Select(Ident(nme.ROOTPKG), nme.scala_), nme.StringContextName) } - else atPos(o2p(start)) { Ident(nme.StringContextName) } + if (currentRun.isScala3Cross) atPos(o2p(start)) { Select(Select(Ident(nme.ROOTPKG), nme.scala_), nme.StringContextName) } + else atPos(o2p(start)) { Ident(nme.StringContextName).updateAttachment(VirtualStringContext) } val t2 = atPos(start) { Apply(t1, partsBuf.toList) } updateAttachment InterpolatedString t2 setPos t2.pos.makeTransparent val t3 = Select(t2, interpolator) setPos t2.pos diff --git a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala index 3ee8f26d9cf1..1b6a62deb85a 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Scanners.scala @@ -17,7 +17,7 @@ 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.Reporting.WarningCategory, WarningCategory.Scala3Migration import scala.tools.nsc.ast.parser.xml.Utility.isNameStart import scala.tools.nsc.settings.ScalaVersion import scala.tools.nsc.util.{CharArrayReader, CharArrayReaderData} @@ -528,12 +528,13 @@ trait Scanners extends ScannersCommon { (sepRegions.isEmpty || sepRegions.head == RBRACE)) { if (pastBlankLine()) insertNL(NEWLINES) else if (!isLeadingInfixOperator) insertNL(NEWLINE) - else if (!currentRun.isScala3) { + else if (!currentRun.isScala3Cross) { val msg = """|Line starts with an operator that in future |will be taken as an infix expression continued from the previous line. |To force the previous interpretation as a separate statement, |add an explicit `;`, add an empty line, or remove spaces after the operator.""" - if (infixMigration) deprecationWarning(msg.stripMargin, "2.13.2") + if (currentRun.isScala3) warning(offset, msg.stripMargin, Scala3Migration) + else if (infixMigration) deprecationWarning(msg.stripMargin, "2.13.2") insertNL(NEWLINE) } } @@ -965,19 +966,19 @@ trait Scanners extends ScannersCommon { if (strVal != null) try { 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) + if (processed != strVal && !currentRun.isScala3Cross) { + 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) { + if (currentRun.isScala3) + warning(pos, msg("ignored in Scala 3"), WarningCategory.Scala3Migration) + else deprecationWarning(pos, msg("deprecated"), since="2.13.2") - strVal = processed - } - else warning(pos, msg("ignored under -Xsource:3"), WarningCategory.Scala3Migration) + strVal = processed } } catch { case ue: StringContext.InvalidUnicodeEscapeException => - if (!currentRun.isScala3) + if (!currentRun.isScala3Cross) syntaxError(offset + 3 + ue.index, ue.getMessage()) } diff --git a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala index e90aabb45e1e..35ca94407aad 100644 --- a/src/compiler/scala/tools/nsc/settings/MutableSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/MutableSettings.scala @@ -217,8 +217,8 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory) def OutputSetting(default: String) = add(new OutputSetting(default)) def PhasesSetting(name: String, descr: String, default: String = "") = add(new PhasesSetting(name, descr, default)) def StringSetting(name: String, arg: String, descr: String, default: String, helpText: Option[String] = None) = add(new StringSetting(name, arg, descr, default, helpText)) - def ScalaVersionSetting(name: String, arg: String, descr: String, initial: ScalaVersion, default: Option[ScalaVersion] = None) = - add(new ScalaVersionSetting(name, arg, descr, initial, default)) + def ScalaVersionSetting(name: String, arg: String, descr: String, initial: ScalaVersion, default: Option[ScalaVersion] = None, helpText: Option[String] = None) = + add(new ScalaVersionSetting(name, arg, descr, initial, default, helpText)) def PathSetting(name: String, descr: String, default: String): PathSetting = { val prepend = StringSetting(name + "/p", "", "", "").internalOnly() val append = StringSetting(name + "/a", "", "", "").internalOnly() @@ -506,10 +506,12 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory) val arg: String, descr: String, val initial: ScalaVersion, - default: Option[ScalaVersion]) + default: Option[ScalaVersion], + helpText: Option[String]) extends Setting(name, descr) { type T = ScalaVersion protected var v: T = initial + protected var sawHelp: Boolean = false // This method is invoked if there are no colonated args. In this case the default value is // used. No arguments are consumed. @@ -522,12 +524,17 @@ class MutableSettings(val errorFn: String => Unit, val pathFactory: PathFactory) } def tryToSetColon(args: List[String]) = args match { + case "help" :: rest if helpText.nonEmpty => sawHelp = true; Some(rest) case x :: xs => value = ScalaVersion(x, errorFn); Some(xs) case nil => Some(nil) } def unparse: List[String] = if (value == NoScalaVersion) Nil else List(s"${name}:${value.unparse}") + override def isHelping: Boolean = sawHelp + + override def help = helpText.get + withHelpSyntax(s"${name}:<${arg}>") } diff --git a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala index 45ed77fbba10..2509b0199a61 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaSettings.scala @@ -124,17 +124,50 @@ trait ScalaSettings extends StandardScalaSettings with Warnings { _: MutableSett val mainClass = StringSetting ("-Xmain-class", "path", "Class for manifest's Main-Class entry (only useful with -d )", "") val sourceReader = StringSetting ("-Xsource-reader", "classname", "Specify a custom method for reading source files.", "") val reporter = StringSetting ("-Xreporter", "classname", "Specify a custom subclass of FilteringReporter for compiler messages.", "scala.tools.nsc.reporters.ConsoleReporter") + private val XsourceHelp = + sm"""|-Xsource:3 is for migrating a codebase, -Xsource:3-cross is for cross-building. + | + |-Xsource:3 isues migration warnings in category `cat=scala3-migration`, + | which by default are promoted to errors under the `-Wconf` configuration. + | Examples of promoted warnings: + | * Implicit definitions must have an explicit type + | * (x: Any) + "" is deprecated + | * Args not adapted to unit value + | * Member classes cannot shadow a same-named class defined in a parent + | * Presence or absence of parentheses in overrides must match exactly + | + |Certain benign syntax features are enabled: + | * case C(xs*) => + | * A & B type intersection + | * import p.* + | * import p.m as n + | * import p.{given, *} + | * Eta-expansion `x.m` of methods without trailing `_` + | + |The following constructs emit a migration warning under -Xsource:3. With + |-Xsource:3-cross the semantics change to match Scala 3 and no warning is issued. + | * Unicode escapes in raw interpolations and triple-quoted strings + | * Leading infix operators continue the previous line + | * Interpolator must be selectable from `scala.StringContext` + | * Case class copy and apply have the same access modifier as the constructor + | * The inferred type of an override is taken from the member it overrides + |""" @nowarn("cat=deprecation") - val source = ScalaVersionSetting ("-Xsource", "version", "Enable features that will be available in a future version of Scala, for purposes of early migration and alpha testing.", initial = ScalaVersion("2.13")).withPostSetHook { s => - if (s.value >= ScalaVersion("3")) + val source = ScalaVersionSetting ("-Xsource", "version", "Enable warnings and features for a future version.", initial = ScalaVersion("2.13"), helpText = Some(XsourceHelp)).withPostSetHook { s => + if (s.value >= ScalaVersion("3")) { isScala3.value = true + if (s.value > ScalaVersion("3")) + isScala3Cross.value = true + } else if (s.value >= ScalaVersion("2.14")) - s.withDeprecationMessage("instead of -Xsource:2.14, use -Xsource:3").value = ScalaVersion("3") + s.withDeprecationMessage("instead of -Xsource:2.14, use -Xsource:3 or -Xsource:3-cross").value = ScalaVersion("3") else if (s.value < ScalaVersion("2.13")) errorFn.apply(s"-Xsource must be at least the current major version (${ScalaVersion("2.13").versionString})") } @deprecated("Use currentRun.isScala3 instead", since="2.13.9") val isScala3 = BooleanSetting ("isScala3", "Is -Xsource Scala 3?").internalOnly() + @deprecated("Use currentRun.isScala3Cross instead", since="2.13.13") + val isScala3Cross = BooleanSetting ("isScala3Cross", "Is -Xsource > Scala 3?").internalOnly() // The previous "-Xsource" option is intended to be used mainly though ^ helper val XnoPatmatAnalysis = BooleanSetting ("-Xno-patmat-analysis", "Don't perform exhaustivity/unreachability analysis. Also, ignore @switch annotation.") diff --git a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala index a01327012999..839b0eb9b5f6 100644 --- a/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala +++ b/src/compiler/scala/tools/nsc/settings/ScalaVersion.scala @@ -24,18 +24,24 @@ sealed abstract class ScalaVersion extends Ordered[ScalaVersion] { def versionString: String = unparse } -/** - * A scala version that sorts higher than all actual versions - */ -case object NoScalaVersion extends ScalaVersion { - def unparse = "none" - +/** A scala version that sorts higher than all actual versions. */ +sealed abstract class MaximalScalaVersion extends ScalaVersion { def compare(that: ScalaVersion): Int = that match { - case NoScalaVersion => 0 + case _: MaximalScalaVersion => 0 case _ => 1 } } +/** If "no version" is specified, assume a maximal version, "the latest". */ +case object NoScalaVersion extends MaximalScalaVersion { + def unparse = "none" +} + +/** Same as `NoScalaVersion` but with a different toString */ +case object Scala3Cross extends MaximalScalaVersion { + def unparse = "3-cross" +} + /** * A specific Scala version, not one of the magic min/max versions. An SpecificScalaVersion * may or may not be a released version - i.e. this same class is used to represent @@ -58,7 +64,7 @@ case class SpecificScalaVersion(major: Int, minor: Int, rev: Int, build: ScalaBu else if (rev > thatRev) 1 else build compare thatBuild case AnyScalaVersion => 1 - case NoScalaVersion => -1 + case _: MaximalScalaVersion => -1 } } @@ -81,13 +87,13 @@ object ScalaVersion { private val dot = """\.""" private val dash = "-" private val vchar = """\d""" //"[^-+.]" - private val vpat = s"(?s)($vchar+)(?:$dot($vchar+)(?:$dot($vchar+)(?:$dash(.*))?)?)?".r + private val vpat = s"(?s)($vchar+)(?:$dot($vchar+)(?:$dot($vchar+))?)?(?:$dash(.+))?".r private val rcpat = """(?i)rc(\d*)""".r private val mspat = """(?i)m(\d*)""".r def apply(versionString: String, errorHandler: String => Unit): ScalaVersion = { def error() = errorHandler( - s"Bad version (${versionString}) not major[.minor[.revision[-suffix]]]" + s"Bad version (${versionString}) not major[.minor[.revision]][-suffix]" ) def toInt(s: String) = s match { @@ -103,12 +109,12 @@ object ScalaVersion { } versionString match { - case "none" => NoScalaVersion - case "" => NoScalaVersion - case "any" => AnyScalaVersion + case "none" | "" => NoScalaVersion + case "3-cross" => Scala3Cross + case "any" => AnyScalaVersion case vpat(majorS, minorS, revS, buildS) => SpecificScalaVersion(toInt(majorS), toInt(minorS), toInt(revS), toBuild(buildS)) - case _ => error() ; AnyScalaVersion + case _ => error(); AnyScalaVersion } } diff --git a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala index ac9c105eb607..2ac3375f22d8 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Adaptations.scala @@ -77,16 +77,15 @@ trait Adaptations { ) } @inline def msg(what: String): String = s"adaptation of an empty argument list by inserting () $what" - @inline def noAdaptation: false = { - context.error(t.pos, adaptWarningMessage(msg("has been removed"), showAdaptation = false)) - false // drop adaptation - } @inline def deprecatedAdaptation: true = { val twist = if (isLeakyTarget) "leaky (Object-receiving) target makes this especially dangerous" else "this is unlikely to be what you want" val text = s"${msg("is deprecated")}: ${twist}" - context.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(text), "2.11.0") + if (currentRun.isScala3) + currentRun.reporting.warning(t.pos, adaptWarningMessage(text), WarningCategory.Scala3Migration, t.symbol) + else + context.deprecationWarning(t.pos, t.symbol, adaptWarningMessage(text), "2.11.0") true // keep adaptation } @inline def warnAdaptation: true = { @@ -109,8 +108,6 @@ trait Adaptations { } if (args.nonEmpty) warnAdaptation - else if (currentRun.isScala3) - noAdaptation else deprecatedAdaptation } diff --git a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala index 9fd8343ea7ce..dc0bb21cf0c4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala +++ b/src/compiler/scala/tools/nsc/typechecker/AnalyzerPlugins.scala @@ -55,7 +55,7 @@ trait AnalyzerPlugins { self: Analyzer with splain.SplainData => * Let analyzer plugins change the types assigned to definitions. For definitions that have * an annotated type, the assigned type is obtained by typing that type tree. Otherwise, the * type is inferred by typing the definition's righthand side, or from the overridden - * member under `-Xsource:3`. + * member under `-Xsource:3-cross`. * * In order to know if the type was inferred, you can query the `wasEmpty` field in the `tpt` * TypeTree of the definition (for DefDef and ValDef). diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index 1391d6c6014d..34f03a5b1c81 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -1075,7 +1075,7 @@ trait Contexts { self: Analyzer => !( // [eed3si9n] ideally I'd like to do this: val fd = currentRun.isScala3 && sym.isDeprecated // but implicit caching currently does not report sym.isDeprecated correctly. - currentRun.isScala3 && (sym == currentRun.runDefinitions.Predef_any2stringaddMethod) + currentRun.isScala3Cross && (sym == currentRun.runDefinitions.Predef_any2stringaddMethod) ) && !(imported && { val e = scope.lookupEntry(name) @@ -1554,7 +1554,6 @@ trait Contexts { self: Analyzer => * 1b) Definitions and declarations that are either inherited, or made * available by a package clause and also defined in the same compilation unit * as the reference to them, have the next highest precedence. - * (Only in -Xsource:3, same precedence as 1 with a warning in Scala 2.) * 2) Explicit imports have next highest precedence. * 3) Wildcard imports have next highest precedence. * 4) Bindings made available by a package clause, diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index ef690434d42d..44c2ac376178 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -1089,7 +1089,7 @@ trait Namers extends MethodSynthesis { /** Computes the type of the body in a ValDef or DefDef, and * assigns the type to the tpt's node. Returns the type. * - * Under `-Xsource:3`, use `pt`, the type of the overridden member. + * Under `-Xsource:3-cross`, use `pt`, the type of the overridden member. * But preserve the precise type of a whitebox macro. * For `def f = macro g`, here we see `def f = xp(g)` the expansion, * not the `isMacro` case: `openMacros` will be nonEmpty. @@ -1117,23 +1117,21 @@ trait Namers extends MethodSynthesis { } } val legacy = dropIllegalStarTypes(widenIfNecessary(tree.symbol, rhsTpe, pt)) - if (inferOverridden) { - if (!(legacy =:= pt) && currentRun.isScala3) { - val pts = pt.toString - val leg = legacy.toString - val help = if (pts != leg) s" instead of $leg" else "" - val msg = s"under -Xsource:3, inferred $pts$help" - val src = currentUnit.source - val pos = { - val eql = src.indexWhere(_ == '=', start = tree.rhs.pos.start, step = -1) - val declEnd = src.indexWhere(!_.isWhitespace, start = eql - 1, step = -1) + 1 - Some(declEnd).filter(_ > 0).map(src.position) - } - val action = pos.map(p => runReporting.codeAction("add explicit type", p.focus, s": $leg", msg)).getOrElse(Nil) - runReporting.warning(tree.pos, msg, WarningCategory.Scala3Migration, tree.symbol, action) + if (inferOverridden && currentRun.isScala3 && !currentRun.isScala3Cross && !(legacy =:= pt)) { + val pts = pt.toString + val leg = legacy.toString + val help = if (pts != leg) s" instead of $leg" else "" + val msg = s"under -Xsource:3-cross, the inferred type changes to $pts$help" + val src = currentUnit.source + val pos = { + val eql = src.indexWhere(_ == '=', start = tree.rhs.pos.start, step = -1) + val declEnd = src.indexWhere(!_.isWhitespace, start = eql - 1, step = -1) + 1 + Some(declEnd).filter(_ > 0).map(src.position) } - pt + val action = pos.map(p => runReporting.codeAction("add explicit type", p.focus, s": $leg", msg)).getOrElse(Nil) + runReporting.warning(tree.pos, msg, WarningCategory.Scala3Migration, tree.symbol, action) } + if (inferOverridden && currentRun.isScala3Cross) pt else legacy.tap(InferredImplicitError(tree, _, context)) }.setPos(tree.pos.focus) tree.tpt.tpe @@ -1455,7 +1453,7 @@ trait Namers extends MethodSynthesis { val resTp = { // When return type is inferred, we don't just use resTpFromOverride -- it must be packed and widened. - // Here, C.f has type String (unless -Xsource:3): + // Here, C.f has type String (unless -Xsource:3-cross): // trait T { def f: Object }; class C extends T { def f = "" } // using resTpFromOverride as expected type allows for the following (C.f has type A): // trait T { def f: A }; class C extends T { implicit def b2a(t: B): A = ???; def f = new B } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 984a1233df5d..777876ab41f9 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -3441,18 +3441,11 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper for (sym <- scope) context.unit.synthetics.get(sym) match { // OPT: shouldAdd is usually true. Call it here, rather than in the outer loop case Some(tree) if shouldAdd(sym) => - def isSyntheticCaseApplyTweaked = tree match { - case DefDef(mods, nme.apply, _, _, _, _) => - sym.owner.sourceModule.companionSymbol.isCaseClass && { - mods.hasFlag(PRIVATE) || mods.privateWithin != tpnme.EMPTY - } - case _ => false - } // if the completer set the IS_ERROR flag, retract the stat (currently only used by applyUnapplyMethodCompleter) if (!sym.initialize.hasFlag(IS_ERROR)) { newStats += typedStat(tree) // might add even more synthetics to the scope - if (currentRun.isScala3 && !sym.owner.isCaseClass && isSyntheticCaseApplyTweaked) - runReporting.warning(tree.pos, "access modifiers for `apply` method are copied from the case class constructor", Scala3Migration, sym) + tree.getAndRemoveAttachment[CaseApplyInheritAccess.type].foreach(_ => + runReporting.warning(tree.pos, "access modifiers for `apply` method are copied from the case class constructor", Scala3Migration, sym)) } context.unit.synthetics -= sym case _ => () @@ -5621,6 +5614,15 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper val fix = runReporting.codeAction("make reference explicit", tree.pos.focusStart, w.fix, w.msg) runReporting.warning(tree.pos, w.msg, cat, context.owner, fix) }) + if (currentRun.isScala3) { + tree.getAndRemoveAttachment[VirtualStringContext.type].foreach(_ => + if (symbol != definitions.StringContextModule) + runReporting.warning( + tree.pos, + s"String interpolations always use scala.StringContext in Scala 3 (${symbol.fullNameString} is used here)", + Scala3Migration, + context.owner)) + } (// this -> Foo.this if (symbol.isThisSym) typed1(This(symbol.owner) setPos tree.pos, mode, pt) diff --git a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala index c7ee89fa2243..74be9c70a44d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Unapplies.scala @@ -16,7 +16,7 @@ package typechecker import scala.annotation.tailrec import symtab.Flags._ import scala.reflect.internal.util.ListOfNil -import scala.tools.nsc.Reporting.WarningCategory +import scala.tools.nsc.Reporting.WarningCategory.Scala3Migration import scala.util.chaining._ /* @@ -98,8 +98,16 @@ trait Unapplies extends ast.TreeDSL { } } - private def applyShouldInheritAccess(mods: Modifiers) = - currentRun.isScala3 && (mods.hasFlag(PRIVATE) || (!mods.hasFlag(PROTECTED) && mods.hasAccessBoundary)) + sealed private trait ApplyAccess + private object Default extends ApplyAccess + private object Warn extends ApplyAccess + private object Inherit extends ApplyAccess + private def applyAccess(mods: Modifiers): ApplyAccess = { + val changeModsIn3 = mods.hasFlag(PRIVATE) || (!mods.hasFlag(PROTECTED) && mods.hasAccessBoundary) + if (currentRun.isScala3Cross && changeModsIn3) Inherit + else if (currentRun.isScala3 && changeModsIn3) Warn + else Default + } /** The module corresponding to a case class; overrides toString to show the module's name */ @@ -108,7 +116,7 @@ trait Unapplies extends ast.TreeDSL { def inheritFromFun = !cdef.mods.hasAbstractFlag && cdef.tparams.isEmpty && (params match { case List(ps) if ps.length <= MaxFunctionArity => true case _ => false - }) && !applyShouldInheritAccess(constrMods(cdef)) + }) && applyAccess(constrMods(cdef)) != Inherit def createFun = { def primaries = params.head map (_.tpt) gen.scalaFunctionConstr(primaries, toIdent(cdef), abstractFun = true) @@ -153,12 +161,12 @@ trait Unapplies extends ast.TreeDSL { */ def caseModuleApplyMeth(cdef: ClassDef): DefDef = { val inheritedMods = constrMods(cdef) + val access = applyAccess(inheritedMods) val mods = - if (applyShouldInheritAccess(inheritedMods)) - (caseMods | (inheritedMods.flags & PRIVATE)).copy(privateWithin = inheritedMods.privateWithin) - else - caseMods - factoryMeth(mods, nme.apply, cdef) + if (access == Inherit) (caseMods | (inheritedMods.flags & PRIVATE)).copy(privateWithin = inheritedMods.privateWithin) + else caseMods + factoryMeth(mods, nme.apply, cdef).tap(m => + if (access == Warn) m.updateAttachment(CaseApplyInheritAccess)) } /** The unapply method corresponding to a case class @@ -272,16 +280,20 @@ trait Unapplies extends ast.TreeDSL { val classTpe = classType(cdef, tparams) val argss = mmap(paramss)(toIdent) val body: Tree = New(classTpe, argss) + val synth = Modifiers(SYNTHETIC) val copyMods = if (currentRun.isScala3) { val inheritedMods = constrMods(cdef) - Modifiers(SYNTHETIC | (inheritedMods.flags & AccessFlags), inheritedMods.privateWithin) - .tap { mods => - if (currentRun.isScala3 && mods != Modifiers(SYNTHETIC)) - runReporting.warning(cdef.pos, "access modifiers for `copy` method are copied from the case class constructor", WarningCategory.Scala3Migration, cdef.symbol) - } + val mods3 = Modifiers(SYNTHETIC | (inheritedMods.flags & AccessFlags), inheritedMods.privateWithin) + if (currentRun.isScala3Cross) + mods3 + else { + if (mods3 != synth) + runReporting.warning(cdef.pos, "access modifiers for `copy` method are copied from the case class constructor", Scala3Migration, cdef.symbol) + synth + } } - else Modifiers(SYNTHETIC) + else synth val copyDefDef = atPos(cdef.pos.focus)( DefDef(copyMods, nme.copy, tparams, paramss, TypeTree(), body) ) diff --git a/src/compiler/scala/tools/reflect/FastStringInterpolator.scala b/src/compiler/scala/tools/reflect/FastStringInterpolator.scala index c3fd72fd695b..6a19c8911598 100644 --- a/src/compiler/scala/tools/reflect/FastStringInterpolator.scala +++ b/src/compiler/scala/tools/reflect/FastStringInterpolator.scala @@ -13,7 +13,7 @@ package scala.tools package reflect -import nsc.Reporting.WarningCategory +import nsc.Reporting.WarningCategory.Scala3Migration trait FastStringInterpolator extends FormatInterpolator { import c.universe._ @@ -46,9 +46,11 @@ trait FastStringInterpolator extends FormatInterpolator { lit.pos.withShift(diffindex) } def msg(fate: String) = s"Unicode escapes in raw interpolations are $fate; use literal characters instead" - if (currentRun.isScala3) { - runReporting.warning(pos, msg("ignored under -Xsource:3"), WarningCategory.Scala3Migration, c.internal.enclosingOwner) + if (currentRun.isScala3Cross) stringVal + else if (currentRun.isScala3) { + runReporting.warning(pos, msg("ignored in Scala 3"), Scala3Migration, c.internal.enclosingOwner) + processed } else { runReporting.deprecationWarning(pos, msg("deprecated"), "2.13.2", "", "") diff --git a/src/reflect/scala/reflect/internal/StdAttachments.scala b/src/reflect/scala/reflect/internal/StdAttachments.scala index 3f8672a0cfb3..6cee9a135dd4 100644 --- a/src/reflect/scala/reflect/internal/StdAttachments.scala +++ b/src/reflect/scala/reflect/internal/StdAttachments.scala @@ -152,6 +152,10 @@ trait StdAttachments { case object InterpolatedString extends PlainAttachment + case object VirtualStringContext extends PlainAttachment + + case object CaseApplyInheritAccess extends PlainAttachment + // Use of _root_ is in correct leading position of selection case object RootSelection extends PlainAttachment diff --git a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala index 8af5d1bae186..5aa32907e6be 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverseForce.scala @@ -78,6 +78,8 @@ trait JavaUniverseForce { self: runtime.JavaUniverse => this.NullaryOverrideAdapted this.ChangeOwnerAttachment this.InterpolatedString + this.VirtualStringContext + this.CaseApplyInheritAccess this.RootSelection this.TypedExpectingUnitAttachment this.FieldTypeInferred diff --git a/test/files/neg/caseclass_private_constructor.scala b/test/files/neg/caseclass_private_constructor.scala index 41b9eb5dcd92..344c23d76be9 100644 --- a/test/files/neg/caseclass_private_constructor.scala +++ b/test/files/neg/caseclass_private_constructor.scala @@ -1,4 +1,4 @@ -// scalac: -Xsource:3 -Wconf:cat=scala3-migration:s +// scalac: -Xsource:3-cross -Wconf:cat=scala3-migration:s case class A private (i: Int) object A diff --git a/test/files/neg/deprecated-options.check b/test/files/neg/deprecated-options.check index d8af67be3f10..31867bd09bf2 100644 --- a/test/files/neg/deprecated-options.check +++ b/test/files/neg/deprecated-options.check @@ -1,4 +1,4 @@ -warning: -Xsource is deprecated: instead of -Xsource:2.14, use -Xsource:3 +warning: -Xsource is deprecated: instead of -Xsource:2.14, use -Xsource:3 or -Xsource:3-cross warning: -Xfuture is deprecated: Not used since 2.13. warning: -optimize is deprecated: Since 2.12, enables -opt:inline:**. This can be dangerous. warning: -Xexperimental is deprecated: Not used since 2.13. diff --git a/test/files/neg/deprecationsFor3.check b/test/files/neg/deprecationsFor3.check new file mode 100644 index 000000000000..898b49176838 --- /dev/null +++ b/test/files/neg/deprecationsFor3.check @@ -0,0 +1,33 @@ +deprecationsFor3.scala:4: warning: Unicode escapes in triple quoted strings are deprecated; use the literal character instead + def inTripleQuoted = """\u0041""" // deprecation + ^ +deprecationsFor3.scala:16: warning: Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. + `x` (42) // migration + ^ +deprecationsFor3.scala:5: warning: Unicode escapes in raw interpolations are deprecated; use literal characters instead + def inRawInterpolation = raw"\u0041" // deprecation + ^ +deprecationsFor3.scala:6: warning: Unicode escapes in raw interpolations are deprecated; use literal characters instead + def inRawTripleQuoted = raw"""\u0041""" // deprecation + ^ +deprecationsFor3.scala:29: warning: Implicit definition should have explicit type (inferred String => Option[Int]) [quickfixable] + implicit def b = _.toIntOption // error + ^ +deprecationsFor3.scala:31: warning: Implicit definition should have explicit type (inferred String) [quickfixable] + implicit def s = "" // error + ^ +deprecationsFor3.scala:30: warning: Implicit definition should have explicit type (inferred Int) [quickfixable] + implicit val i = 0 // error + ^ +deprecationsFor3.scala:34: warning: method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call + +object AnyPlus { def f(xs: List[Int]) = xs + ";" } + ^ +deprecationsFor3.scala:38: warning: shadowing a nested class of a parent is deprecated but class X shadows class X defined in class A; rename the class to something else + class B extends A { class X; def f = new X } + ^ +error: No warnings can be incurred under -Werror. +9 warnings +1 error diff --git a/test/files/neg/deprecationsFor3.scala b/test/files/neg/deprecationsFor3.scala new file mode 100644 index 000000000000..43925f1b1491 --- /dev/null +++ b/test/files/neg/deprecationsFor3.scala @@ -0,0 +1,39 @@ +//> using options -deprecation -Xmigration -Werror + +object UnicodeEscapes { + def inTripleQuoted = """\u0041""" // deprecation + def inRawInterpolation = raw"\u0041" // deprecation + def inRawTripleQuoted = raw"""\u0041""" // deprecation +} + +object InfixNewline extends App { + class K { def x(y: Int) = 0 } + + def x(a: Int) = 1 + + def ok = { + (new K) + `x` (42) // migration + } +} + +case class CaseCompanionMods private (x: Int) // nothing + +trait InferredBase { def f: Object } +object InferredSub extends InferredBase { def f = "a" } // nothing + +trait ExplicitImplicitsBase { + implicit def b: String => Option[Int] +} +object ExplicitImplicits extends ExplicitImplicitsBase { + implicit def b = _.toIntOption // error + implicit val i = 0 // error + implicit def s = "" // error +} + +object AnyPlus { def f(xs: List[Int]) = xs + ";" } + +object NameShadowing { + class A { class X } + class B extends A { class X; def f = new X } +} diff --git a/test/files/neg/implicit-any2stringadd.scala b/test/files/neg/implicit-any2stringadd.scala index 7e86c89cd31f..0692d9a7b9cb 100644 --- a/test/files/neg/implicit-any2stringadd.scala +++ b/test/files/neg/implicit-any2stringadd.scala @@ -1,4 +1,4 @@ -// scalac: -Xsource:3 -Vimplicits +// scalac: -Xsource:3-cross -Vimplicits // object Test { true + "what" diff --git a/test/files/neg/multiLineOps-b.scala b/test/files/neg/multiLineOps-b.scala index 5d1f5682b738..00763244086c 100644 --- a/test/files/neg/multiLineOps-b.scala +++ b/test/files/neg/multiLineOps-b.scala @@ -1,4 +1,4 @@ -// scalac: -Werror -Xsource:3 +//> using options -Werror -Xsource:3-cross class Test { val b1 = { diff --git a/test/files/neg/multiLineOps-c.scala b/test/files/neg/multiLineOps-c.scala index d5004b1ba863..af3f255cc04e 100644 --- a/test/files/neg/multiLineOps-c.scala +++ b/test/files/neg/multiLineOps-c.scala @@ -1,4 +1,4 @@ -// scalac: -Werror -Xsource:3 +//> using options -Werror -Xsource:3-cross class Test { val x = 42 diff --git a/test/files/neg/multiLineOps.scala b/test/files/neg/multiLineOps.scala index 4a92fd9f2c0c..1d8e9164014e 100644 --- a/test/files/neg/multiLineOps.scala +++ b/test/files/neg/multiLineOps.scala @@ -1,4 +1,4 @@ -// scalac: -Werror -Xlint -Xsource:3 +//> using options -Werror -Xlint -Xsource:3-cross class Test { val x = 1 diff --git a/test/files/neg/source3Xneg.check b/test/files/neg/source3Xneg.check new file mode 100644 index 000000000000..ff9e1a67fe3a --- /dev/null +++ b/test/files/neg/source3Xneg.check @@ -0,0 +1,22 @@ +source3Xneg.scala:47: error: value + is not a member of List[Int] +object AnyPlus { def f(xs: List[Int]) = xs + ";" } + ^ +source3Xneg.scala:56: error: method copy in class CaseCompanionMods cannot be accessed as a member of CaseCompanionMods from object Test + CaseCompanionMods.i.copy(CaseCompanionMods(2).x) // 2 errors + ^ +source3Xneg.scala:56: error: method apply in object CaseCompanionMods cannot be accessed as a member of object CaseCompanionMods from object Test +error after rewriting to CaseCompanionMods. +possible cause: maybe a wrong Dynamic method signature? + CaseCompanionMods.i.copy(CaseCompanionMods(2).x) // 2 errors + ^ +source3Xneg.scala:60: error: value toUpperCase is not a member of Object + InferredSub.f.toUpperCase // error + ^ +source3Xneg.scala:44: warning: Implicit definition must have explicit type (inferred String) [quickfixable] + implicit def s = "" // error + ^ +source3Xneg.scala:43: warning: Implicit definition must have explicit type (inferred Int) [quickfixable] + implicit val i = 0 // error + ^ +2 warnings +4 errors diff --git a/test/files/neg/source3Xneg.scala b/test/files/neg/source3Xneg.scala new file mode 100644 index 000000000000..9b852a5b2219 --- /dev/null +++ b/test/files/neg/source3Xneg.scala @@ -0,0 +1,62 @@ +//> using options -deprecation -Xsource:3-cross -Wconf:cat=scala3-migration:w -Werror + +// StringContext hygiene +class SC1 { + class Impl(parts: Any*) { + def s(args: Any*) = "hello, old world" + } + object StringContext { + def apply(parts: Any*) = new Impl(parts: _*) + } + def name = "Scala3" + def test = s"hello, $name" // ok +} + +object UnicodeEscapes { + def inTripleQuoted = """\u0041""" // ok + def inRawInterpolation = raw"\u0041" // ok + def inRawTripleQuoted = raw"""\u0041""" // ok +} + +object InfixNewline extends App { + class K { def x(y: Int) = 0 } + + def x(a: Int) = 1 + + def ok = { + (new K) + `x` (42) // ok + } +} + +case class CaseCompanionMods private (x: Int) // ok +object CaseCompanionMods { def i = CaseCompanionMods(1) } + +trait InferredBase { def f: Object } +object InferredSub extends InferredBase { def f = "a" } // nothing + +trait ExplicitImplicitsBase { + implicit def b: String => Option[Int] +} +object ExplicitImplicits extends ExplicitImplicitsBase { + implicit def b = _.toIntOption // ok + implicit val i = 0 // error + implicit def s = "" // error +} + +object AnyPlus { def f(xs: List[Int]) = xs + ";" } + +object NameShadowing { + class A { class X } + class B extends A { class X; def f = new X } +} + +object Test { + locally { + CaseCompanionMods.i.copy(CaseCompanionMods(2).x) // 2 errors + } + + locally { + InferredSub.f.toUpperCase // error + } +} diff --git a/test/files/neg/source3XnegRefchecks.check b/test/files/neg/source3XnegRefchecks.check new file mode 100644 index 000000000000..acdb8a271e36 --- /dev/null +++ b/test/files/neg/source3XnegRefchecks.check @@ -0,0 +1,6 @@ +source3XnegRefchecks.scala:5: warning: shadowing a nested class of a parent is deprecated but class X shadows class X defined in class A; rename the class to something else + class B extends A { class X; def f = new X } + ^ +error: No warnings can be incurred under -Werror. +1 warning +1 error diff --git a/test/files/neg/source3XnegRefchecks.scala b/test/files/neg/source3XnegRefchecks.scala new file mode 100644 index 000000000000..c2f9ac623fb8 --- /dev/null +++ b/test/files/neg/source3XnegRefchecks.scala @@ -0,0 +1,6 @@ +//> using options -deprecation -Xsource:3-cross -Wconf:cat=scala3-migration:w -Werror + +object NameShadowing { + class A { class X } + class B extends A { class X; def f = new X } +} diff --git a/test/files/neg/source3neg.check b/test/files/neg/source3neg.check new file mode 100644 index 000000000000..bcd2fa2d3943 --- /dev/null +++ b/test/files/neg/source3neg.check @@ -0,0 +1,45 @@ +source3neg.scala:16: warning: Unicode escapes in triple quoted strings are ignored in Scala 3; use the literal character instead + def inTripleQuoted = """\u0041""" // error + ^ +source3neg.scala:28: warning: Line starts with an operator that in future +will be taken as an infix expression continued from the previous line. +To force the previous interpretation as a separate statement, +add an explicit `;`, add an empty line, or remove spaces after the operator. + `x` (42) // error + ^ +source3neg.scala:12: warning: String interpolations always use scala.StringContext in Scala 3 (SC1.StringContext is used here) + def test = s"hello, $name" // error + ^ +source3neg.scala:17: warning: Unicode escapes in raw interpolations are ignored in Scala 3; use literal characters instead + def inRawInterpolation = raw"\u0041" // error + ^ +source3neg.scala:18: warning: Unicode escapes in raw interpolations are ignored in Scala 3; use literal characters instead + def inRawTripleQuoted = raw"""\u0041""" // error + ^ +source3neg.scala:32: warning: access modifiers for `copy` method are copied from the case class constructor +case class CaseCompanionMods private (x: Int) // 2 errors + ^ +source3neg.scala:32: warning: access modifiers for `apply` method are copied from the case class constructor +case class CaseCompanionMods private (x: Int) // 2 errors + ^ +source3neg.scala:36: warning: under -Xsource:3-cross, the inferred type changes to Object instead of String [quickfixable] +object InferredSub extends InferredBase { def f = "a" } // error + ^ +source3neg.scala:42: warning: Implicit definition must have explicit type (inferred String => Option[Int]) [quickfixable] + implicit def b = _.toIntOption // error + ^ +source3neg.scala:44: warning: Implicit definition must have explicit type (inferred String) [quickfixable] + implicit def s = "" // error + ^ +source3neg.scala:43: warning: Implicit definition must have explicit type (inferred Int) [quickfixable] + implicit val i = 0 // error + ^ +source3neg.scala:47: warning: method any2stringadd in object Predef is deprecated (since 2.13.0): Implicit injection of + is deprecated. Convert to String to call + +object AnyPlus { def f(xs: List[Int]) = xs + ";" } + ^ +source3neg.scala:51: warning: shadowing a nested class of a parent is deprecated but class X shadows class X defined in class A; rename the class to something else + class B extends A { class X; def f = new X } + ^ +error: No warnings can be incurred under -Werror. +13 warnings +1 error diff --git a/test/files/neg/source3neg.scala b/test/files/neg/source3neg.scala new file mode 100644 index 000000000000..c05a6944a0f8 --- /dev/null +++ b/test/files/neg/source3neg.scala @@ -0,0 +1,62 @@ +//> using options -deprecation -Xsource:3 -Wconf:cat=scala3-migration:w -Werror + +// StringContext hygiene +class SC1 { + class Impl(parts: Any*) { + def s(args: Any*) = "hello, old world" + } + object StringContext { + def apply(parts: Any*) = new Impl(parts: _*) + } + def name = "Scala3" + def test = s"hello, $name" // error +} + +object UnicodeEscapes { + def inTripleQuoted = """\u0041""" // error + def inRawInterpolation = raw"\u0041" // error + def inRawTripleQuoted = raw"""\u0041""" // error +} + +object InfixNewline extends App { + class K { def x(y: Int) = 0 } + + def x(a: Int) = 1 + + def ok = { + (new K) + `x` (42) // error + } +} + +case class CaseCompanionMods private (x: Int) // 2 errors +object CaseCompanionMods { def i = CaseCompanionMods(1) } + +trait InferredBase { def f: Object } +object InferredSub extends InferredBase { def f = "a" } // error + +trait ExplicitImplicitsBase { + implicit def b: String => Option[Int] +} +object ExplicitImplicits extends ExplicitImplicitsBase { + implicit def b = _.toIntOption // error + implicit val i = 0 // error + implicit def s = "" // error +} + +object AnyPlus { def f(xs: List[Int]) = xs + ";" } + +object NameShadowing { + class A { class X } + class B extends A { class X; def f = new X } +} + +object Test { + locally { + CaseCompanionMods.i.copy(CaseCompanionMods(2).x) // ok + } + + locally { + InferredSub.f.toUpperCase // ok + } +} \ No newline at end of file diff --git a/test/files/neg/t12798-migration.check b/test/files/neg/t12798-migration.check index eb5ee58de77c..5b6a353828ac 100644 --- a/test/files/neg/t12798-migration.check +++ b/test/files/neg/t12798-migration.check @@ -32,16 +32,16 @@ class `misuse of underscore`[_] t12798-migration.scala:48: warning: early initializers are deprecated; use trait parameters instead. class `early bird` extends { val x = "hello, world" } with Runnable { def run() = println(x) } ^ -t12798-migration.scala:17: warning: Unicode escapes in raw interpolations are ignored under -Xsource:3; use literal characters instead +t12798-migration.scala:17: warning: Unicode escapes in raw interpolations are ignored in Scala 3; use literal characters instead def f = raw"\u0043 is for $entry" ^ -t12798-migration.scala:18: warning: Unicode escapes in raw interpolations are ignored under -Xsource:3; use literal characters instead +t12798-migration.scala:18: warning: Unicode escapes in raw interpolations are ignored in Scala 3; use literal characters instead def g = raw"""\u0043 is for Cat""" ^ t12798-migration.scala:50: warning: access modifiers for `copy` method are copied from the case class constructor case class `case mods propagate` private (s: String) ^ -t12798-migration.scala:60: warning: under -Xsource:3, inferred Option[Int] instead of Some[Int] [quickfixable] +t12798-migration.scala:60: warning: under -Xsource:3-cross, the inferred type changes to Option[Int] instead of Some[Int] [quickfixable] override def f = Some(27) ^ t12798-migration.scala:50: warning: access modifiers for `apply` method are copied from the case class constructor diff --git a/test/files/neg/t12798.check b/test/files/neg/t12798.check index 1f60929e72a4..9c88c1698d77 100644 --- a/test/files/neg/t12798.check +++ b/test/files/neg/t12798.check @@ -50,12 +50,12 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration 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 +t12798.scala:17: error: Unicode escapes in raw interpolations are ignored in Scala 3; use literal characters instead Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=interpolated unicode such as C.f 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 +t12798.scala:18: error: Unicode escapes in raw interpolations are ignored in Scala 3; use literal characters instead Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=interpolated unicode such as C.g def g = raw"""\u0043 is for Cat""" @@ -65,7 +65,7 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=case mods propagate case class `case mods propagate` private (s: String) ^ -t12798.scala:60: error: under -Xsource:3, inferred Option[Int] instead of Some[Int] [quickfixable] +t12798.scala:60: error: under -Xsource:3-cross, the inferred type changes to Option[Int] instead of Some[Int] [quickfixable] Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=Child.f override def f = Some(27) diff --git a/test/files/neg/t5265b.check b/test/files/neg/t5265b.check index 985f15935c6a..2bc7768075fb 100644 --- a/test/files/neg/t5265b.check +++ b/test/files/neg/t5265b.check @@ -3,7 +3,7 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=Missing.tsMissing implicit val tsMissing = new T[String] {} // warn val in trait ^ -t5265b.scala:20: error: under -Xsource:3, inferred T[String] [quickfixable] +t5265b.scala:20: error: under -Xsource:3-cross, the inferred type changes to T[String] [quickfixable] Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=Child.tsChild implicit val tsChild = new T[String] {} // nowarn because inferred from overridden diff --git a/test/files/neg/t7212.check b/test/files/neg/t7212.check index c1dada6f9eab..951569cfec3d 100644 --- a/test/files/neg/t7212.check +++ b/test/files/neg/t7212.check @@ -1,26 +1,12 @@ -t7212.scala:8: error: type mismatch; - found : Object - required: String - val s: String = k.f - ^ -t7212.scala:14: error: type mismatch; - found : Object - required: String - val s: String = f.f - ^ -t7212.scala:21: error: type mismatch; - found : Object - required: String - val s: String = w.f - ^ -t7212.scala:5: warning: under -Xsource:3, inferred Object instead of String [quickfixable] +t7212.scala:5: warning: under -Xsource:3-cross, the inferred type changes to Object instead of String [quickfixable] class K extends T { def f = "" } ^ -t7212.scala:11: warning: under -Xsource:3, inferred Object instead of String [quickfixable] +t7212.scala:11: warning: under -Xsource:3-cross, the inferred type changes to Object instead of String [quickfixable] class F extends T { val f = "" } ^ -t7212.scala:17: warning: under -Xsource:3, inferred Object instead of String [quickfixable] +t7212.scala:17: warning: under -Xsource:3-cross, the inferred type changes to Object instead of String [quickfixable] trait V extends T { var f = "" } ^ +error: No warnings can be incurred under -Werror. 3 warnings -3 errors +1 error diff --git a/test/files/neg/t7212.scala b/test/files/neg/t7212.scala index 328431249cb4..033123c69cd2 100644 --- a/test/files/neg/t7212.scala +++ b/test/files/neg/t7212.scala @@ -1,5 +1,5 @@ -// scalac: -Xmigration -Xsource:3 +//> using options -Werror -Xmigration -Xsource:3 trait T { def f: Object } class K extends T { def f = "" } diff --git a/test/files/neg/t7212b.check b/test/files/neg/t7212b.check new file mode 100644 index 000000000000..181f58769da4 --- /dev/null +++ b/test/files/neg/t7212b.check @@ -0,0 +1,16 @@ +t7212b.scala:8: error: type mismatch; + found : Object + required: String + val s: String = k.f + ^ +t7212b.scala:14: error: type mismatch; + found : Object + required: String + val s: String = f.f + ^ +t7212b.scala:21: error: type mismatch; + found : Object + required: String + val s: String = w.f + ^ +3 errors diff --git a/test/files/neg/t7212b.scala b/test/files/neg/t7212b.scala new file mode 100644 index 000000000000..bbc684381fee --- /dev/null +++ b/test/files/neg/t7212b.scala @@ -0,0 +1,22 @@ + +//> using options -Xmigration -Xsource:3-cross + +trait T { def f: Object } +class K extends T { def f = "" } +object K { + val k = new K + val s: String = k.f +} + +class F extends T { val f = "" } +object F { + val f = new F + val s: String = f.f +} + +trait V extends T { var f = "" } +class W extends V +object W { + val w = new W + val s: String = w.f +} diff --git a/test/files/neg/t8035-deprecated.check b/test/files/neg/t8035-deprecated.check index 18b8587c64fd..46054f04982b 100644 --- a/test/files/neg/t8035-deprecated.check +++ b/test/files/neg/t8035-deprecated.check @@ -4,6 +4,9 @@ t8035-deprecated.scala:4: warning: adaptation of an empty argument list by inser after adaptation: SetOps((): Unit) List(1,2,3).toSet() ^ +t8035-deprecated.scala:4: warning: a type was inferred to be `AnyVal`; this may indicate a programming error. + List(1,2,3).toSet() + ^ t8035-deprecated.scala:7: warning: adaptation of an empty argument list by inserting () is deprecated: this is unlikely to be what you want signature: A(x: T): Foo.A[T] given arguments: @@ -17,5 +20,5 @@ t8035-deprecated.scala:11: warning: adaptation of an empty argument list by inse sdf.format() ^ error: No warnings can be incurred under -Werror. -3 warnings +4 warnings 1 error diff --git a/test/files/neg/t8035-deprecated.scala b/test/files/neg/t8035-deprecated.scala index f2d1a3d66af0..bb8a93302b19 100644 --- a/test/files/neg/t8035-deprecated.scala +++ b/test/files/neg/t8035-deprecated.scala @@ -1,4 +1,4 @@ -// scalac: -deprecation -Xfatal-warnings +//> using options -Werror -Xlint // object Foo { List(1,2,3).toSet() diff --git a/test/files/neg/t8035-removed.check b/test/files/neg/t8035-removed.check index 0769b2bce3ec..79aa9ed88a62 100644 --- a/test/files/neg/t8035-removed.check +++ b/test/files/neg/t8035-removed.check @@ -1,21 +1,30 @@ -t8035-removed.scala:4: error: adaptation of an empty argument list by inserting () has been removed +t8035-removed.scala:4: error: adaptation of an empty argument list by inserting () is deprecated: this is unlikely to be what you want signature: SetOps.apply(elem: A): Boolean given arguments: + after adaptation: SetOps((): Unit) +Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. +Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=scala.collection.SetOps.apply List(1,2,3).toSet() ^ -t8035-removed.scala:7: error: adaptation of an empty argument list by inserting () has been removed +t8035-removed.scala:4: warning: a type was inferred to be `AnyVal`; this may indicate a programming error. + List(1,2,3).toSet() + ^ +t8035-removed.scala:7: error: adaptation of an empty argument list by inserting () is deprecated: this is unlikely to be what you want signature: A(x: T): Foo.A[T] given arguments: + after adaptation: new A((): Unit) +Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. +Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=Foo.A. new A ^ -t8035-removed.scala:11: error: adaptation of an empty argument list by inserting () has been removed +t8035-removed.scala:11: error: adaptation of an empty argument list by inserting () is deprecated: leaky (Object-receiving) target makes this especially dangerous signature: Format.format(x$1: Object): String given arguments: + after adaptation: Format.format((): Unit) +Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. +Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=java.text.Format.format sdf.format() ^ -t8035-removed.scala:4: warning: a type was inferred to be `AnyVal`; this may indicate a programming error. - List(1,2,3).toSet() - ^ t8035-removed.scala:14: warning: adapted the argument list to the expected 2-tuple: add additional parens instead signature: List.::[B >: A](elem: B): List[B] given arguments: 42, 27 diff --git a/test/files/neg/t8035-removed.scala b/test/files/neg/t8035-removed.scala index bada37b7d2f1..d06113bbff4a 100644 --- a/test/files/neg/t8035-removed.scala +++ b/test/files/neg/t8035-removed.scala @@ -1,4 +1,4 @@ -// scalac: -Xsource:3.0 -Xlint -Werror +//> using options -Werror -Xlint -Xsource:3-cross // object Foo { List(1,2,3).toSet() diff --git a/test/files/pos/infixed.scala b/test/files/pos/infixed.scala index d740c6ba94f2..5004b90f4ac9 100644 --- a/test/files/pos/infixed.scala +++ b/test/files/pos/infixed.scala @@ -1,4 +1,4 @@ -// scalac: -Xsource:3 +// scalac: -Xsource:3-cross class K { def x(y: Int) = 0 } diff --git a/test/files/pos/leading-infix-op.scala b/test/files/pos/leading-infix-op.scala index 4b60aa67b8c1..d812f4460f4e 100644 --- a/test/files/pos/leading-infix-op.scala +++ b/test/files/pos/leading-infix-op.scala @@ -1,5 +1,5 @@ -// scalac: -Xsource:3 +// scalac: -Xsource:3-cross trait T { def f(x: Int): Boolean = diff --git a/test/files/pos/multiLineOps.scala b/test/files/pos/multiLineOps.scala index d17ebbad1f81..f5717ebc3fb7 100644 --- a/test/files/pos/multiLineOps.scala +++ b/test/files/pos/multiLineOps.scala @@ -1,4 +1,4 @@ -// scalac: -Werror -Xsource:3 +// scalac: -Werror -Xsource:3-cross class Channel { def ! (msg: String): Channel = this diff --git a/test/files/pos/t7212.scala b/test/files/pos/t7212.scala index d732d040f641..29285c53d87e 100644 --- a/test/files/pos/t7212.scala +++ b/test/files/pos/t7212.scala @@ -1,5 +1,5 @@ -// scalac: -Xsource:3 -Xmigration +// scalac: -Xsource:3-cross -Xmigration class A { def f: Option[String] = Some("hello, world") diff --git a/test/files/pos/t7212b/ScalaThing.scala b/test/files/pos/t7212b/ScalaThing.scala index 0bfd2ba054c1..b0facb72771e 100644 --- a/test/files/pos/t7212b/ScalaThing.scala +++ b/test/files/pos/t7212b/ScalaThing.scala @@ -1,5 +1,5 @@ -// scalac: -Xsource:3 -Xmigration +// scalac: -Xsource:3-cross -Xmigration class ScalaThing extends JavaThing { override def remove() = ??? diff --git a/test/files/run/interpolator-hygiene.scala b/test/files/run/interpolator-hygiene.scala deleted file mode 100644 index 3a752c8db9d8..000000000000 --- a/test/files/run/interpolator-hygiene.scala +++ /dev/null @@ -1,31 +0,0 @@ -// scalac: -Xsource:3 -class C { - class X(parts: Any*) { - def s(args: Any*) = "hello, work" - } - object StringContext { - def apply(parts: Any*) = new X(parts: _*) - } - def name = "Scala3" - def test = s"hello, $name" -} -class D { - import D.* - class StringContext(parts: Any*) { - def x(args: Any*) = "hello, work" - } - object StringContext { - def apply(parts: Any*) = new StringContext(parts: _*) - } - def name = "Scala3" - def test = x"hello, $name" -} -object D { - implicit class x(val sc: StringContext) extends AnyVal { - def x(args: Any*) = "hello, world" - } -} -object Test extends App { - assert(new C().test == "hello, Scala3") - assert(new D().test == "hello, world") -} diff --git a/test/files/run/multiLineOps.scala b/test/files/run/multiLineOps.scala index ef319d9210dc..2b51b95e9262 100644 --- a/test/files/run/multiLineOps.scala +++ b/test/files/run/multiLineOps.scala @@ -1,4 +1,4 @@ -// scalac: -Xsource:3 +//> using options -Xsource:3-cross // // was: without backticks, "not found: value +" (but parsed here as +a * 6, where backticks fool the lexer) // now: + is taken as "solo" infix op diff --git a/test/files/run/productElementName.scala b/test/files/run/productElementName.scala index 18dcaad0935a..ff09355c39bd 100644 --- a/test/files/run/productElementName.scala +++ b/test/files/run/productElementName.scala @@ -1,4 +1,5 @@ -// scalac: -Xsource:3 +//> using options -Xsource:3-cross + import scala.tools.testkit.AssertUtil.assertThrown import scala.util.chaining.* import org.junit.Assert.assertEquals diff --git a/test/files/run/source3Xrun.scala b/test/files/run/source3Xrun.scala new file mode 100644 index 000000000000..8ebb44d49f2a --- /dev/null +++ b/test/files/run/source3Xrun.scala @@ -0,0 +1,71 @@ +//> using options -Xsource:3-cross + +// StringContext hygiene +class SC1 { + class Impl(parts: Any*) { + def s(args: Any*) = "hello, old world" + } + object StringContext { + def apply(parts: Any*) = new Impl(parts: _*) + } + def name = "Scala3" + def test = s"hello, $name" +} + +class SC2 { + import SC2.* + class Impl(parts: Any*) { + def x(args: Any*) = "hello, old world" } + object StringContext { + def apply(parts: Any*) = new Impl(parts: _*) + } + def name = "Scala3" + def test = x"hello, $name" +} +object SC2 { + implicit class x(val sc: StringContext) extends AnyVal { + def x(args: Any*) = "hello, world" + } +} + +object UnicodeEscapes { + def inTripleQuoted = """\u0041""" + def inRawInterpolation = raw"\u0041" + def inRawTripleQuoted = raw"""\u0041""" +} + +object InfixNewline extends App { + class K { def x(y: Int) = 0 } + + def x(a: Int) = 1 + + def ok = { + (new K) + `x` (42) + } +} + +case class CaseCompanionMods private (x: Int) +object CaseCompanionMods { def i = CaseCompanionMods(1) } + +object Test extends App { + locally { + assert(new SC1().test == "hello, Scala3") + assert(new SC2().test == "hello, world") + } + + locally { + val asList = List('\\', 'u', '0', '0', '4', '1') + assert(asList == UnicodeEscapes.inTripleQuoted.toList) + assert(asList == UnicodeEscapes.inRawInterpolation.toList) + assert(asList == UnicodeEscapes.inRawTripleQuoted.toList) + } + + locally { + assert(InfixNewline.ok == 0) + } + + locally { + CaseCompanionMods.i + } +} diff --git a/test/files/run/source3run.scala b/test/files/run/source3run.scala new file mode 100644 index 000000000000..a2f9c6847c83 --- /dev/null +++ b/test/files/run/source3run.scala @@ -0,0 +1,78 @@ +//> using options -Wconf:cat=scala3-migration:s -Xsource:3 + +// StringContext hygiene +class SC1 { + class Impl(parts: Any*) { + def s(args: Any*) = "hello, old world" + } + object StringContext { + def apply(parts: Any*) = new Impl(parts: _*) + } + def name = "Scala3" + def test = s"hello, $name" +} + +class SC2 { + import SC2.* + class Impl(parts: Any*) { + def x(args: Any*) = "hello, old world" } + object StringContext { + def apply(parts: Any*) = new Impl(parts: _*) + } + def name = "Scala3" + def test = x"hello, $name" +} +object SC2 { + implicit class x(val sc: StringContext) extends AnyVal { + def x(args: Any*) = "hello, world" + } +} + +object UnicodeEscapes { + def inTripleQuoted = """\u0041""" + def inRawInterpolation = raw"\u0041" + def inRawTripleQuoted = raw"""\u0041""" +} + +object InfixNewline extends App { + class K { def x(y: Int) = 0 } + + def x(a: Int) = 1 + + def ok = { + (new K) + `x` (42) + } +} + +case class CaseCompanionMods private (x: Int) +object CaseCompanionMods { def i = CaseCompanionMods(1) } + +trait InferredBase { def f: Object } +object InferredSub extends InferredBase { def f = "a" } + +object Test extends App { + locally { + assert(new SC1().test == "hello, old world") + assert(new SC2().test == "hello, old world") + } + + locally { + val asList = List('A') + assert(asList == UnicodeEscapes.inTripleQuoted.toList) + assert(asList == UnicodeEscapes.inRawInterpolation.toList) + assert(asList == UnicodeEscapes.inRawTripleQuoted.toList) + } + + locally { + assert(InfixNewline.ok == 1) + } + + locally { + CaseCompanionMods.i.copy(x = CaseCompanionMods(2).x) + } + + locally { + assert(InferredSub.f.toUpperCase == "A") + } +} diff --git a/test/files/run/t12071.scala b/test/files/run/t12071.scala index 5950647a1526..e22f73b8550e 100644 --- a/test/files/run/t12071.scala +++ b/test/files/run/t12071.scala @@ -1,4 +1,4 @@ -// scalac: -Werror -Xlint -Xsource:3 +//> using options -Werror -Xlint -Xsource:3-cross class C { def `c c`(n: Int): Int = n + 1 diff --git a/test/files/run/t3220-214.check b/test/files/run/t3220-214.check deleted file mode 100644 index 2556d27a1488..000000000000 --- a/test/files/run/t3220-214.check +++ /dev/null @@ -1,9 +0,0 @@ -t3220-214.scala:4: warning: Unicode escapes in triple quoted strings are ignored under -Xsource:3; use the literal character instead - def inTripleQuoted = """\u000A""" - ^ -t3220-214.scala:5: warning: Unicode escapes in raw interpolations are ignored under -Xsource:3; use literal characters instead - def inRawInterpolation = raw"\u000A" - ^ -t3220-214.scala:6: warning: Unicode escapes in raw interpolations are ignored under -Xsource:3; use literal characters instead - def inRawTripleQuoted = raw"""\u000A""" - ^ diff --git a/test/files/run/t3220-214.scala b/test/files/run/t3220-214.scala index 7b711b1b79b1..3ca0634a6d52 100644 --- a/test/files/run/t3220-214.scala +++ b/test/files/run/t3220-214.scala @@ -1,4 +1,4 @@ -// scalac: -Xsource:3 -Xmigration +//> using options -Xmigration -Xsource:3-cross object Literals214 { def inTripleQuoted = """\u000A""" diff --git a/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala b/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala index 768dfd82264f..37ff8f373766 100644 --- a/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala +++ b/test/junit/scala/tools/nsc/settings/ScalaVersionTest.scala @@ -31,14 +31,18 @@ class ScalaVersionTest { assertEquals(V(2,11,7,Development("maybegood")), ScalaVersion("2.11.7-maybegood")) assertEquals(V(2,11,7,Development("RCCola")), ScalaVersion("2.11.7-RCCola")) assertEquals(V(2,11,7,Development("RC1.5")), ScalaVersion("2.11.7-RC1.5")) - assertEquals(V(2,11,7,Development("")), ScalaVersion("2.11.7-")) + assertEquals(V(2,11,0,Development("Z")), ScalaVersion("2.11-Z")) assertEquals(V(2,11,7,Development("0.5")), ScalaVersion("2.11.7-0.5")) assertEquals(V(2,11,7,Development("devbuild\nt9167")), ScalaVersion("2.11.7-devbuild\nt9167")) assertEquals(V(2,11,7,Development("final")), ScalaVersion("2.11.7-final")) // oh really assertEquals(NoScalaVersion, ScalaVersion("none")) + assertSame(NoScalaVersion, ScalaVersion("none")) + assertEquals(Scala3Cross, ScalaVersion("3-cross")) + assertSame(Scala3Cross, ScalaVersion("3-cross")) assertEquals(AnyScalaVersion, ScalaVersion("any")) + assertSame(AnyScalaVersion, ScalaVersion("any")) assertThrows[NumberFormatException] { ScalaVersion("2.11.7.2") } assertThrows[NumberFormatException] { ScalaVersion("2.11.7.beta") } @@ -50,11 +54,14 @@ class ScalaVersionTest { assertThrows[NumberFormatException] { ScalaVersion("2..") } assertThrows[NumberFormatException] { ScalaVersion("2...") } assertThrows[NumberFormatException] { ScalaVersion("2-") } - assertThrows[NumberFormatException] { ScalaVersion("2-.") } // scalacheck territory + //assertThrows[NumberFormatException] { ScalaVersion("2-.") } // scalacheck territory + assertEquals(V(2,0,0,Development(".")), ScalaVersion("2-.")) // build labels are arbitrary text + assertEquals(V(2,11,0,Development("ok")), ScalaVersion("2.11-ok")) // build labels are arbitrary text + assertThrows[NumberFormatException] { ScalaVersion("2.11.7-") } assertThrows[NumberFormatException] { ScalaVersion("any.7") } - assertThrows[NumberFormatException] ( ScalaVersion("2.11-ok"), _ == - "Bad version (2.11-ok) not major[.minor[.revision[-suffix]]]" ) + assertThrows[NumberFormatException] ( ScalaVersion("2.11-"), _ == + "Bad version (2.11-) not major[.minor[.revision]][-suffix]" ) } From 3950943ea2714d87ec2367048fc5499a6c59c7da Mon Sep 17 00:00:00 2001 From: Lukas Rytz Date: Tue, 21 Nov 2023 12:14:07 +0100 Subject: [PATCH 2/2] un-deprecate package object inheritance --- .../scala/tools/nsc/ast/parser/Parsers.scala | 5 ----- .../neg/deprecate_package_object_extends.check | 13 ------------- .../neg/deprecate_package_object_extends.scala | 5 ----- test/files/neg/t11921b.check | 8 +------- test/files/neg/t12798-migration.check | 6 +----- test/files/neg/t12798.check | 8 +------- test/files/neg/t12816.check | 8 +------- test/files/neg/t12816b.check | 8 +------- 8 files changed, 5 insertions(+), 56 deletions(-) delete mode 100644 test/files/neg/deprecate_package_object_extends.check delete mode 100644 test/files/neg/deprecate_package_object_extends.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index f0938f755f49..14dd845076f1 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -3392,11 +3392,6 @@ self => val templateOffset = if (body.isEmpty && in.lastOffset < tstart) in.lastOffset else tstart val templatePos = o2p(templateOffset) - // warn now if user wrote parents for package object; `gen.mkParents` adds AnyRef to parents - if (currentRun.isScala3 && name == nme.PACKAGEkw && !parents.isEmpty) - 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. if (inScalaRootPackage && ScalaValueClassNames.contains(name)) diff --git a/test/files/neg/deprecate_package_object_extends.check b/test/files/neg/deprecate_package_object_extends.check deleted file mode 100644 index a2563d7b4edb..000000000000 --- a/test/files/neg/deprecate_package_object_extends.check +++ /dev/null @@ -1,13 +0,0 @@ -deprecate_package_object_extends.scala:3: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); -drop the `extends` clause or use a regular object instead -Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. -Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration -package object foo extends C - ^ -deprecate_package_object_extends.scala:5: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); -drop the `extends` clause or use a regular object instead -Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. -Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration -package foo2 { object `package` extends C } - ^ -2 errors diff --git a/test/files/neg/deprecate_package_object_extends.scala b/test/files/neg/deprecate_package_object_extends.scala deleted file mode 100644 index b5c8d8def301..000000000000 --- a/test/files/neg/deprecate_package_object_extends.scala +++ /dev/null @@ -1,5 +0,0 @@ -// scalac: -Xsource:3 -class C -package object foo extends C - -package foo2 { object `package` extends C } diff --git a/test/files/neg/t11921b.check b/test/files/neg/t11921b.check index 0a073ee5c3d9..c223004a3048 100644 --- a/test/files/neg/t11921b.check +++ b/test/files/neg/t11921b.check @@ -1,12 +1,6 @@ t11921b.scala:135: error: could not find implicit value for parameter i: Int def u = t // doesn't compile in Scala 2 (maybe there's a ticket for that) ^ -t11921b.scala:151: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); -drop the `extends` clause or use a regular object instead -Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. -Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration -package object pt12850 extends t12850 { - ^ t11921b.scala:11: error: reference to x is ambiguous; it is both defined in the enclosing object Test and inherited in the enclosing class D as value x (defined in class C) In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope. @@ -79,4 +73,4 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=test10.C.v def v = t(lo) // error ^ -10 errors +9 errors diff --git a/test/files/neg/t12798-migration.check b/test/files/neg/t12798-migration.check index 5b6a353828ac..2e229140359e 100644 --- a/test/files/neg/t12798-migration.check +++ b/test/files/neg/t12798-migration.check @@ -6,10 +6,6 @@ To express the assignment expression, wrap it in brackets, e.g., `{ z = ... }`. t12798-migration.scala:25: warning: unary prefix operator definition with empty parameter list is unsupported: instead, remove () to declare as `def unary_- = -42` [quickfixable] def unary_-() = -42 ^ -t12798-migration.scala:28: warning: 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-migration.scala:33: warning: procedure syntax is deprecated for constructors: add `=`, as in method definition [quickfixable] def this(s: String) { this() } ^ @@ -50,5 +46,5 @@ case class `case mods propagate` private (s: String) t12798-migration.scala:52: warning: access modifiers for `apply` method are copied from the case class constructor case class `copyless case mods propagate` private (s: String) { ^ -15 warnings +14 warnings 1 error diff --git a/test/files/neg/t12798.check b/test/files/neg/t12798.check index 9c88c1698d77..39620c5b0f2c 100644 --- a/test/files/neg/t12798.check +++ b/test/files/neg/t12798.check @@ -8,12 +8,6 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration 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 -Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. -Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration -package object tester extends Runnable { - ^ t12798.scala:33: error: procedure syntax is deprecated for constructors: add `=`, as in method definition [quickfixable] Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration @@ -75,4 +69,4 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=copyless case mods propagate.apply case class `copyless case mods propagate` private (s: String) { ^ -15 errors +14 errors diff --git a/test/files/neg/t12816.check b/test/files/neg/t12816.check index e33d1dec434c..d4192cedca69 100644 --- a/test/files/neg/t12816.check +++ b/test/files/neg/t12816.check @@ -1,9 +1,3 @@ -t12816.scala:8: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); -drop the `extends` clause or use a regular object instead -Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. -Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration -package object p extends U { - ^ t12816.scala:29: error: reference to c is ambiguous; it is both defined in the enclosing package p and inherited in the enclosing trait RR as method c (defined in trait T) In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope. @@ -22,4 +16,4 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=p.RR.n3 def n3: Z // warn ^ -3 errors +2 errors diff --git a/test/files/neg/t12816b.check b/test/files/neg/t12816b.check index 606f2c579007..770e50f8834a 100644 --- a/test/files/neg/t12816b.check +++ b/test/files/neg/t12816b.check @@ -1,9 +1,3 @@ -A.scala:5: error: package object inheritance is deprecated (https://github.com/scala/scala-dev/issues/441); -drop the `extends` clause or use a regular object instead -Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to filter them or add -Xmigration to demote them to warnings. -Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration -package object p extends U { - ^ B.scala:19: error: reference to c is ambiguous; it is both defined in the enclosing package p and inherited in the enclosing trait RR as method c (defined in trait T) In Scala 2, symbols inherited from a superclass shadow symbols defined in an outer scope. @@ -22,4 +16,4 @@ Scala 3 migration messages are errors under -Xsource:3. Use -Wconf / @nowarn to Applicable -Wconf / @nowarn filters for this fatal warning: msg=, cat=scala3-migration, site=p.RR.n3 def n3: Z // warn ^ -3 errors +2 errors