Skip to content

Commit

Permalink
Disallow _ for wildcard arguments of types and use ?
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolasstucki committed Nov 1, 2023
1 parent 1e95432 commit 405f2b0
Show file tree
Hide file tree
Showing 463 changed files with 1,020 additions and 1,006 deletions.
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/config/Feature.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ object Feature:
val dependent = experimental("dependent")
val erasedDefinitions = experimental("erasedDefinitions")
val symbolLiterals = deprecated("symbolLiterals")
val underscoreWildcards = deprecated("underscoreWildcards")
val fewerBraces = experimental("fewerBraces")
val saferExceptions = experimental("saferExceptions")
val clauseInterleaving = experimental("clauseInterleaving")
Expand Down
9 changes: 6 additions & 3 deletions compiler/src/dotty/tools/dotc/parsing/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1856,9 +1856,12 @@ object Parsers {
val start = in.skipToken()
Ident(tpnme.USCOREkw).withSpan(Span(start, in.lastOffset, start))
else
if sourceVersion.isAtLeast(future) then
deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead")
patch(source, Span(in.offset, in.offset + 1), "?")
if !in.featureEnabled(Feature.underscoreWildcards) then
report.errorOrMigrationWarning(
em"`_` is deprecated for wildcard arguments of types: use `?` instead${rewriteNotice(`3.4-migration`)}",
in.sourcePos(), from = `3.4`)
if sourceVersion == `3.4-migration` then
patch(source, Span(in.offset, in.offset + 1), "?")
val start = in.skipToken()
typeBounds().withSpan(Span(start, in.lastOffset, start))
// Allow symbols -_ and +_ through for compatibility with code written using kind-projector in Scala 3 underscore mode.
Expand Down
5 changes: 2 additions & 3 deletions compiler/test-resources/repl/i13208.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//> using options -source:future -deprecation
//> using options -language:`3.4-migration` -deprecation
scala> type M[X] = X match { case Int => String case _ => Int }
scala> type N[X] = X match { case List[_] => Int }
1 warning found
-- Deprecation Warning: --------------------------------------------------------
-- Error: ----------------------------------------------------------------------
1 | type N[X] = X match { case List[_] => Int }
| ^
| `_` is deprecated for wildcard arguments of types: use `?` instead
2 changes: 1 addition & 1 deletion compiler/test-resources/repl/i6643
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ scala> import scala.collection._
scala>:type 1
Int

scala> object IterableTest { def g[CC[_] <: Iterable[_] with IterableOps[_, _, _]](from: CC[Int]): IterableFactory[CC] = ??? }
scala> object IterableTest { def g[CC[_] <: Iterable[?] with IterableOps[?, ?, ?]](from: CC[Int]): IterableFactory[CC] = ??? }
// defined object IterableTest
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ class DottyBytecodeTests extends DottyBytecodeTest {
| def test =
| try print("foo")
| catch {
| case _: scala.runtime.NonLocalReturnControl[_] => ()
| case _: scala.runtime.NonLocalReturnControl[?] => ()
| }
|}
""".stripMargin
Expand Down
12 changes: 6 additions & 6 deletions library/src/scala/Tuple.scala
Original file line number Diff line number Diff line change
Expand Up @@ -97,25 +97,25 @@ object Tuple {

/** Type of the head of a tuple */
type Head[X <: NonEmptyTuple] = X match {
case x *: _ => x
case x *: xs => x
}

/** Type of the initial part of the tuple without its last element */
type Init[X <: Tuple] <: Tuple = X match {
case _ *: EmptyTuple => EmptyTuple
case x *: EmptyTuple => EmptyTuple
case x *: xs =>
x *: Init[xs]
}

/** Type of the tail of a tuple */
type Tail[X <: NonEmptyTuple] <: Tuple = X match {
case _ *: xs => xs
case x *: xs => xs
}

/** Type of the last element of a tuple */
type Last[X <: Tuple] = X match {
case x *: EmptyTuple => x
case _ *: xs => Last[xs]
case x *: xs => Last[xs]
}

/** Type of the concatenation of two tuples */
Expand Down Expand Up @@ -182,8 +182,8 @@ object Tuple {
*/
type Zip[T1 <: Tuple, T2 <: Tuple] <: Tuple = (T1, T2) match {
case (h1 *: t1, h2 *: t2) => (h1, h2) *: Zip[t1, t2]
case (EmptyTuple, _) => EmptyTuple
case (_, EmptyTuple) => EmptyTuple
case (EmptyTuple, ?) => EmptyTuple
case (?, EmptyTuple) => EmptyTuple
case _ => Tuple
}

Expand Down
4 changes: 4 additions & 0 deletions library/src/scala/runtime/stdLibPatches/language.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ object language:
*/
@compileTimeOnly("`symbolLiterals` can only be used at compile time in import statements")
object symbolLiterals

/** TODO */
@compileTimeOnly("`underscoreWildcards` can only be used at compile time in import statements")
object underscoreWildcards
end deprecated

/** Where imported, auto-tupling is disabled.
Expand Down
7 changes: 6 additions & 1 deletion project/Build.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1008,7 +1008,10 @@ object Build {
Seq("-sourcepath", ((Compile/sourceManaged).value / "scala-library-src").toString)
},
Compile / doc / scalacOptions += "-Ydocument-synthetic-types",
scalacOptions += "-Ycompile-scala2-library",
scalacOptions ++= Seq(
"-Ycompile-scala2-library",
"-language:deprecated.underscoreWildcards",
),
scalacOptions -= "-Xfatal-warnings",
ivyConfigurations += SourceDeps.hide,
transitiveClassifiers := Seq("sources"),
Expand Down Expand Up @@ -1292,6 +1295,7 @@ object Build {
mtagsSharedSources
} (Set(mtagsSharedSourceJar)).toSeq
}.taskValue,
scalacOptions += "-language:deprecated.underscoreWildcards",
)
}

Expand Down Expand Up @@ -1361,6 +1365,7 @@ object Build {
dependsOn(`scala3-library-bootstrappedJS`).
settings(
bspEnabled := false,
scalacOptions += "-language:deprecated.underscoreWildcards",
scalacOptions --= Seq("-Xfatal-warnings", "-deprecation"),

// Required to run Scala.js tests.
Expand Down
3 changes: 0 additions & 3 deletions sbt-test/compilerReporter/i14576/Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,3 @@ object Test:

// private[this] and = _ are deprecated under -source:future
private[this] var x: AnyRef = _

// under -source:future, `_` is deprecated for wildcard arguments of types: use `?` instead
val xs: List[_] = Nil
2 changes: 1 addition & 1 deletion sbt-test/compilerReporter/i14576/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ lazy val root = (project in file("."))
},
assertDeprecationSummary := {
assert {
FakePrintWriter.messages.exists(_.contains("there were 3 deprecation warnings; re-run with -deprecation for details"))
FakePrintWriter.messages.exists(_.contains("there were 2 deprecation warnings; re-run with -deprecation for details"))
}
},
assertNoDeprecationSummary := {
Expand Down
66 changes: 33 additions & 33 deletions sbt-test/scala2-compat/erasure/dottyApp/Api.scala
Original file line number Diff line number Diff line change
Expand Up @@ -156,41 +156,41 @@ class Z {
def int_63(x: AnyVal with Int): Unit = {}

def intARRAY_64(x: Array[Int with Singleton]): Unit = {}
def intARRAY_65(x: Array[_ <: Int]): Unit = {}
def intARRAY_66(x: Array[_ <: Int with Singleton]): Unit = {}
def intARRAY_67(x: Array[_ <: Singleton with Int]): Unit = {}
def intARRAY_68(x: Array[_ <: Int with Any]): Unit = {}
def intARRAY_69(x: Array[_ <: Any with Int]): Unit = {}
def intARRAY_70(x: Array[_ <: Int with AnyVal]): Unit = {}
def intARRAY_71(x: Array[_ <: AnyVal with Int]): Unit = {}
def intARRAY_71a(x: Array[_ <: Int | Int]): Unit = {}
def intARRAY_71b(x: Array[_ <: 1 | 2]): Unit = {}
def intARRAY_65(x: Array[? <: Int]): Unit = {}
def intARRAY_66(x: Array[? <: Int with Singleton]): Unit = {}
def intARRAY_67(x: Array[? <: Singleton with Int]): Unit = {}
def intARRAY_68(x: Array[? <: Int with Any]): Unit = {}
def intARRAY_69(x: Array[? <: Any with Int]): Unit = {}
def intARRAY_70(x: Array[? <: Int with AnyVal]): Unit = {}
def intARRAY_71(x: Array[? <: AnyVal with Int]): Unit = {}
def intARRAY_71a(x: Array[? <: Int | Int]): Unit = {}
def intARRAY_71b(x: Array[? <: 1 | 2]): Unit = {}

def stringARRAY_72(x: Array[String with Singleton]): Unit = {}
def stringARRAY_73(x: Array[_ <: String]): Unit = {}
def stringARRAY_74(x: Array[_ <: String with Singleton]): Unit = {}
def stringARRAY_75(x: Array[_ <: Singleton with String]): Unit = {}
def stringARRAY_76(x: Array[_ <: String with Any]): Unit = {}
def stringARRAY_77(x: Array[_ <: Any with String]): Unit = {}
def stringARRAY_78(x: Array[_ <: String with AnyRef]): Unit = {}
def stringARRAY_79(x: Array[_ <: AnyRef with String]): Unit = {}
def stringARRAY_79a(x: Array[_ <: String | String]): Unit = {}
def stringARRAY_79b(x: Array[_ <: "a" | "b"]): Unit = {}

def object_80(x: Array[_ <: Singleton]): Unit = {}
def object_81(x: Array[_ <: AnyVal]): Unit = {}
def objectARRAY_82(x: Array[_ <: AnyRef]): Unit = {}
def object_83(x: Array[_ <: Any]): Unit = {}
def object_83a(x: Array[_ <: Matchable]): Unit = {}
def object_83b(x: Array[_ <: Int | Double]): Unit = {}
def object_83c(x: Array[_ <: String | Int]): Unit = {}
def object_83d(x: Array[_ <: Int | Matchable]): Unit = {}
def object_83e(x: Array[_ <: AnyRef | AnyVal]): Unit = {}

def serializableARRAY_84(x: Array[_ <: Serializable]): Unit = {}
def univARRAY_85(x: Array[_ <: Univ]): Unit = {}
def aARRAY_86(x: Array[_ <: A]): Unit = {}
def aARRAY_87(x: Array[_ <: A with B]): Unit = {}
def stringARRAY_73(x: Array[? <: String]): Unit = {}
def stringARRAY_74(x: Array[? <: String with Singleton]): Unit = {}
def stringARRAY_75(x: Array[? <: Singleton with String]): Unit = {}
def stringARRAY_76(x: Array[? <: String with Any]): Unit = {}
def stringARRAY_77(x: Array[? <: Any with String]): Unit = {}
def stringARRAY_78(x: Array[? <: String with AnyRef]): Unit = {}
def stringARRAY_79(x: Array[? <: AnyRef with String]): Unit = {}
def stringARRAY_79a(x: Array[? <: String | String]): Unit = {}
def stringARRAY_79b(x: Array[? <: "a" | "b"]): Unit = {}

def object_80(x: Array[? <: Singleton]): Unit = {}
def object_81(x: Array[? <: AnyVal]): Unit = {}
def objectARRAY_82(x: Array[? <: AnyRef]): Unit = {}
def object_83(x: Array[? <: Any]): Unit = {}
def object_83a(x: Array[? <: Matchable]): Unit = {}
def object_83b(x: Array[? <: Int | Double]): Unit = {}
def object_83c(x: Array[? <: String | Int]): Unit = {}
def object_83d(x: Array[? <: Int | Matchable]): Unit = {}
def object_83e(x: Array[? <: AnyRef | AnyVal]): Unit = {}

def serializableARRAY_84(x: Array[? <: Serializable]): Unit = {}
def univARRAY_85(x: Array[? <: Univ]): Unit = {}
def aARRAY_86(x: Array[? <: A]): Unit = {}
def aARRAY_87(x: Array[? <: A with B]): Unit = {}

def objectARRAY_88(x: Array[Any]): Unit = {}
def objectARRAY_89(x: Array[AnyRef]): Unit = {}
Expand Down
2 changes: 1 addition & 1 deletion sbt-test/scala2-compat/i11173/app/App.scala
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import i11173.Bar

def test(x: Bar[_]): Unit = ()
def test(x: Bar[?]): Unit = ()
2 changes: 1 addition & 1 deletion scaladoc-testcases/src/tests/exports1.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class A: //unexpected
= 1
type HKT[T[_], X] //expected: final type HKT = [T[_], X] =>> a.HKT[T, X]
= T[X]
type SomeRandomType = (List[_] | Seq[_]) & String //expected: final type SomeRandomType = a.SomeRandomType
type SomeRandomType = (List[?] | Seq[?]) & String //expected: final type SomeRandomType = a.SomeRandomType
def x[T[_], X](x: X): HKT[T, X] //expected: def x[T[_], X](x: X): A.this.HKT[T, X]
= ???
def fn[T, U]: T => U
Expand Down
2 changes: 1 addition & 1 deletion scaladoc-testcases/src/tests/hkts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ trait Case14[C[_]]
class SomeClass extends Case14[List]


def method1[E, T](value: List[_ >: E]): Int = 0
def method1[E, T](value: List[? >: E]): Int = 0
def method2[F[+X] <: Option[X], A](fa: F[A]): A = fa.get

import scala.collection.immutable.ArraySeq
Expand Down
2 changes: 1 addition & 1 deletion scaladoc-testcases/src/tests/snippetTestcase2.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package tests
package snippetTestcase2

trait Quotes2[A] {
val r1: r1Module[_] = ???
val r1: r1Module[?] = ???
trait r1Module[A] {
type X
object Y {
Expand Down
2 changes: 1 addition & 1 deletion scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,5 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings:
"List of quick links that is displayed in the header of documentation."
)

def scaladocSpecificSettings: Set[Setting[_]] =
def scaladocSpecificSettings: Set[Setting[?]] =
Set(sourceLinks, legacySourceLink, syntax, revision, externalDocumentationMappings, socialLinks, skipById, skipByRegex, deprecatedSkipPackages, docRootContent, snippetCompiler, generateInkuire, defaultTemplate, scastieConfiguration, quickLinks)
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class StaticSiteLoader(val root: File, val args: Scaladoc.Args)(using StaticSite
(("1900","01","01"), name)

def dateFrom(tf: TemplateFile, default: String = "1900-01-01"): String =
val pageSettings = tf.settings.get("page").collect{ case m: Map[String @unchecked, _] => m }
val pageSettings = tf.settings.get("page").collect{ case m: Map[String @unchecked, ?] => m }
pageSettings.flatMap(_.get("date").collect{ case s: String => s}).getOrElse(default) // blogs without date are last

val posts = List(rootPath.resolve("_posts"))
Expand Down
2 changes: 1 addition & 1 deletion scaladoc/src/dotty/tools/scaladoc/site/common.scala
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def loadTemplateFile(file: File, defaultTitle: Option[TemplateName] = None)(usin
}.map(_.stripPrefix("\"").stripSuffix("\""))

def listSetting(settings: Map[String, Object], name: String): Option[List[String]] = settings.get(name).map {
case elems: List[_] => elems.zipWithIndex.map {
case elems: List[?] => elems.zipWithIndex.map {
case (s: String, _) => s
case (other, index) =>
throw new RuntimeException(s"Expected a string at index $index for $name in $file but got $other")
Expand Down
4 changes: 2 additions & 2 deletions scaladoc/src/dotty/tools/scaladoc/site/templates.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ case class TemplateFile(
)

def asJavaElement(o: Object): Object = o match
case m: Map[_, _] => m.transform {
case m: Map[?, ?] => m.transform {
case (k: String, v: Object) => asJavaElement(v)
}.asJava
case l: List[_] => l.map(x => asJavaElement(x.asInstanceOf[Object])).asJava
case l: List[?] => l.map(x => asJavaElement(x.asInstanceOf[Object])).asJava
case other => other

// Library requires mutable maps..
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import dotty.tools.dotc.util.{ SourcePosition, NoSourcePosition, SourceFile, NoS
import scala.util.{ Try, Success, Failure }

class SnippetCompiler(
val snippetCompilerSettings: Seq[SnippetCompilerSetting[_]],
val snippetCompilerSettings: Seq[SnippetCompilerSetting[?]],
target: AbstractFile = new VirtualDirectory("(memory)")
):
object SnippetDriver extends Driver:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ case class DocFlexmarkRenderer(renderLink: (DocLink, String) => String)
html.raw(renderLink(node.target, node.body))

object Render extends NodeRenderer:
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[_]] =
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[?]] =
JSet(
new NodeRenderingHandler(classOf[DocLinkNode], Handler),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ object SectionRenderingExtension extends HtmlRenderer.HtmlRendererExtension:


object Render extends NodeRenderer:
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[_]] =
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[?]] =
JSet(
new NodeRenderingHandler(classOf[Section], SectionHandler),
new NodeRenderingHandler(classOf[AnchorLink], AnchorLinkHandler)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ object SnippetRenderingExtension extends HtmlRenderer.HtmlRendererExtension:
html.raw(SnippetRenderer.renderSnippet(node.getContentChars.toString, node.getInfo.toString.split(" ").headOption))

object Render extends NodeRenderer:
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[_]] =
override def getNodeRenderingHandlers: JSet[NodeRenderingHandler[?]] =
JSet(
new NodeRenderingHandler(classOf[ExtendedFencedCodeBlock], ExtendedFencedCodeBlockHandler),
new NodeRenderingHandler(classOf[FencedCodeBlock], FencedCodeBlockHandler)
Expand Down
2 changes: 1 addition & 1 deletion staging/src/scala/quoted/staging/ExprCompilationUnit.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ import dotty.tools.dotc.CompilationUnit
import dotty.tools.dotc.util.NoSource

/** Compilation unit containing the contents of a quoted expression */
private class ExprCompilationUnit(val exprBuilder: Quotes => Expr[_]) extends CompilationUnit(NoSource)
private class ExprCompilationUnit(val exprBuilder: Quotes => Expr[?]) extends CompilationUnit(NoSource)
2 changes: 1 addition & 1 deletion staging/src/scala/quoted/staging/QuoteCompiler.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ private class QuoteCompiler extends Compiler:
/** Unpickle and optionally compile the expression.
* Returns either `Left` with name of the classfile generated or `Right` with the value contained in the expression.
*/
def compileExpr(exprBuilder: Quotes => Expr[_]): Either[String, Any] =
def compileExpr(exprBuilder: Quotes => Expr[?]): Either[String, Any] =
val units = new ExprCompilationUnit(exprBuilder) :: Nil
compileUnits(units)
result
Expand Down
2 changes: 1 addition & 1 deletion tests/bench/inductive-implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ package shapeless {
def ::[HH](h : HH) : HH :: H :: T = shapeless.::(h, this)

override def toString = head match {
case _: ::[_, _] => "("+head.toString+") :: "+tail.toString
case _: ::[?, ?] => "("+head.toString+") :: "+tail.toString
case _ => head.toString+" :: "+tail.toString
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/explicit-nulls/pos/array.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class Foo {

def test = {
// accept any array of string
def f(xs: Array[_ >: String <: String | Null] | Null): Unit = ???
def f(xs: Array[? >: String <: String | Null] | Null): Unit = ???

val a1: Array[String] = ???
val a2: Array[String] | Null = ???
Expand Down
4 changes: 2 additions & 2 deletions tests/explicit-nulls/pos/flow-inline.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ class TreeOps {
abstract class Tree[A, B](val key: A, val value: B)
class RedTree[A, B](override val key: A, override val value: B) extends Tree[A, B](key, value)

private transparent inline def isRedTree(tree: Tree[_, _] | Null) =
(tree != null) && tree.isInstanceOf[RedTree[_, _]]
private transparent inline def isRedTree(tree: Tree[?, ?] | Null) =
(tree != null) && tree.isInstanceOf[RedTree[?, ?]]

def foo[A, B](tree: Tree[A, B] | Null): Unit = {
if (isRedTree(tree)) {
Expand Down
8 changes: 4 additions & 4 deletions tests/generic-java-signatures/arrayBound.scala
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
class Foo[
T <: Array[_],
T <: Array[?],
U <: Array[T],
V <: java.util.List[Array[T]],
W <: java.util.List[_ <: java.util.Date],
X <: java.util.HashMap[Array[_], java.util.ArrayList[_ <: java.util.Date]],
W <: java.util.List[? <: java.util.Date],
X <: java.util.HashMap[Array[?], java.util.ArrayList[? <: java.util.Date]],
T1,
U1 <: Array[T1],
V1 <: Array[Array[T1]]
]
object Test {
def main(args: Array[String]): Unit = {
val tParams = classOf[Foo[_, _, _, _, _, _, _, _]].getTypeParameters()
val tParams = classOf[Foo[?, ?, ?, ?, ?, ?, ?, ?]].getTypeParameters()
tParams.foreach { tp =>
println(tp.getName + " <: " + tp.getBounds.map(_.getTypeName).mkString(", "))
}
Expand Down
Loading

0 comments on commit 405f2b0

Please sign in to comment.