Skip to content

Commit

Permalink
Deprecate calling a type ? without backticks
Browse files Browse the repository at this point in the history
scala#9560 introduced a new meaning for
`?` under `-Xsource:3`, but to smooth out the migration it'd be nice if
we could also enable this meaning by default. Before doing so, let's
deprecate any current usage of `?` as a type that isn't wrapped in
backticks.
  • Loading branch information
smarter committed May 10, 2021
1 parent db9cad0 commit 38791f5
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 4 deletions.
24 changes: 20 additions & 4 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Expand Up @@ -725,6 +725,14 @@ self =>

def isWildcardType = in.token == USCORE || isScala3WildcardType
def isScala3WildcardType = settings.isScala3 && isRawIdent && in.name == raw.QMARK
def checkQMarkUsage() =
if (!settings.isScala3 && isRawIdent && in.name == raw.QMARK)
deprecationWarning(in.offset,
"`?` in a type will be interpreted as a wildcard in the future, wrap it in backticks to keep the current meaning.", "2.13.6")
def checkQMarkDefinition() =
if (isRawIdent && in.name == raw.QMARK)
deprecationWarning(in.offset,
"using `?` as a type name will require backticks in the future.", "2.13.6")

def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT
def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw
Expand Down Expand Up @@ -1148,11 +1156,13 @@ self =>
} else if (isWildcardType) {
val scala3Wildcard = isScala3WildcardType
wildcardType(in.skipToken(), scala3Wildcard)
} else
} else {
checkQMarkUsage()
path(thisOK = false, typeOK = true) match {
case r @ SingletonTypeTree(_) => r
case r => convertToTypeId(r)
}
}
})
}
}
Expand Down Expand Up @@ -1296,8 +1306,11 @@ self =>
def rawIdent(): Name = try in.name finally in.nextToken()

/** For when it's known already to be a type name. */
def identForType(): TypeName = ident().toTypeName
def identForType(skipIt: Boolean): TypeName = ident(skipIt).toTypeName
def identForType(): TypeName = identForType(skipIt = true)
def identForType(skipIt: Boolean): TypeName = {
checkQMarkDefinition()
ident(skipIt).toTypeName
}

def identOrMacro(): Name = if (isMacro) rawIdent() else ident()

Expand Down Expand Up @@ -2065,12 +2078,14 @@ self =>
in.nextToken()
if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start, scala3Wildcard)
else atPos(start) { Bind(tpnme.WILDCARD, EmptyTree) }
} else
} else {
checkQMarkUsage()
typ() match {
case Ident(name: TypeName) if nme.isVariableName(name) =>
atPos(start) { Bind(name, EmptyTree) }
case t => t
}
}
}

/** {{{
Expand Down Expand Up @@ -2569,6 +2584,7 @@ self =>
}
}
val nameOffset = in.offset
checkQMarkDefinition()
// TODO AM: freshTermName(o2p(in.skipToken()), "_$$"), will need to update test suite
val pname: TypeName = wildcardOrIdent().toTypeName
val param = atPos(start, nameOffset) {
Expand Down
42 changes: 42 additions & 0 deletions test/files/neg/qmark-deprecated.check
@@ -0,0 +1,42 @@
qmark-deprecated.scala:4: warning: using `?` as a type name will require backticks in the future.
class Foo[?] // error
^
qmark-deprecated.scala:6: warning: using `?` as a type name will require backticks in the future.
class Bar[M[?] <: List[?]] // errors
^
qmark-deprecated.scala:6: warning: `?` in a type will be interpreted as a wildcard in the future, wrap it in backticks to keep the current meaning.
class Bar[M[?] <: List[?]] // errors
^
qmark-deprecated.scala:10: warning: using `?` as a type name will require backticks in the future.
class ? { val x = 1 } // error
^
qmark-deprecated.scala:16: warning: using `?` as a type name will require backticks in the future.
trait ? // error
^
qmark-deprecated.scala:22: warning: using `?` as a type name will require backticks in the future.
type ? = Int // error
^
qmark-deprecated.scala:27: warning: `?` in a type will be interpreted as a wildcard in the future, wrap it in backticks to keep the current meaning.
val x: Array[?] = new Array[?](0) // errors
^
qmark-deprecated.scala:27: warning: `?` in a type will be interpreted as a wildcard in the future, wrap it in backticks to keep the current meaning.
val x: Array[?] = new Array[?](0) // errors
^
qmark-deprecated.scala:30: warning: `?` in a type will be interpreted as a wildcard in the future, wrap it in backticks to keep the current meaning.
def foo1[T <: Array[?]](x: T): Array[?] = x // errors
^
qmark-deprecated.scala:30: warning: `?` in a type will be interpreted as a wildcard in the future, wrap it in backticks to keep the current meaning.
def foo1[T <: Array[?]](x: T): Array[?] = x // errors
^
qmark-deprecated.scala:33: warning: using `?` as a type name will require backticks in the future.
def bar1[?] = {} // error
^
qmark-deprecated.scala:35: warning: using `?` as a type name will require backticks in the future.
def bar3[M[?]] = {} // error
^
qmark-deprecated.scala:38: warning: using `?` as a type name will require backticks in the future.
type A[?] = Int // error
^
error: No warnings can be incurred under -Werror.
13 warnings
1 error
40 changes: 40 additions & 0 deletions test/files/neg/qmark-deprecated.scala
@@ -0,0 +1,40 @@
// scalac: -deprecation -Xfatal-warnings
//

class Foo[?] // error
class Foo2[`?`] // ok
class Bar[M[?] <: List[?]] // errors
class Bar2[M[`?`] <: List[`?`]] // ok

object G {
class ? { val x = 1 } // error
}
object G2 {
class `?` { val x = 1 } // ok
}
object H {
trait ? // error
}
object H2 {
trait `?` // ok
}
object I {
type ? = Int // error
}
object I2 {
type `?` = Int // ok

val x: Array[?] = new Array[?](0) // errors
val y: Array[`?`] = new Array[`?`](0) // ok

def foo1[T <: Array[?]](x: T): Array[?] = x // errors
def foo2[T <: Array[`?`]](x: T): Array[`?`] = x // ok

def bar1[?] = {} // error
def bar2[`?`] = {} // ok
def bar3[M[?]] = {} // error
def bar4[M[`?`]] = {} // error

type A[?] = Int // error
type B[`?`] = Int // ok
}

0 comments on commit 38791f5

Please sign in to comment.