Skip to content

Commit

Permalink
Differentiate Scala 2 and Scala 3 wildcard identifier names
Browse files Browse the repository at this point in the history
This change names wildcards written with Scala 3 `?` syntax with `?$N` pattern instead of `_$N` used for Scala 2 wildcards

There are two reasons for it:

- To allow `kind-projector` to implement Scala 3 underscore syntax for type lambdas by transforming old-style underscores, but leaving Scala 3 underscores intact
- To show a mildly more relevant error message, since a wildcard introduced by `?` will now also have a name with `?` in the error message
  • Loading branch information
neko-kai committed May 9, 2021
1 parent c60318f commit ac638c2
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 11 deletions.
22 changes: 11 additions & 11 deletions src/compiler/scala/tools/nsc/ast/parser/Parsers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -722,9 +722,8 @@ self =>
def isRawBar = isRawIdent && in.name == raw.BAR
def isRawIdent = in.token == IDENTIFIER

def isWildcardType =
in.token == USCORE ||
currentRun.isScala3 && isRawIdent && in.name == raw.QMARK
def isWildcardType = in.token == USCORE || isScala3WildcardType
def isScala3WildcardType = currentRun.isScala3 && isRawIdent && in.name == raw.QMARK

def isIdent = in.token == IDENTIFIER || in.token == BACKQUOTED_IDENT
def isMacro = in.token == IDENTIFIER && in.name == nme.MACROkw
Expand Down Expand Up @@ -1083,10 +1082,10 @@ self =>
in.nextToken()
in.nextToken()
atPos(start)(Ident(identName))
}
else if (isWildcardType)
wildcardType(in.skipToken())
else
} else if (isWildcardType) {
val scala3Wildcard = isScala3WildcardType
wildcardType(in.skipToken(), scala3Wildcard)
} else
path(thisOK = false, typeOK = true) match {
case r @ SingletonTypeTree(_) => r
case r => convertToTypeId(r)
Expand Down Expand Up @@ -1483,8 +1482,8 @@ self =>
* WildcardType ::= `_' TypeBounds
* }}}
*/
def wildcardType(start: Offset) = {
val pname = freshTypeName("_$")
def wildcardType(start: Offset, qmark: Boolean) = {
val pname = if (qmark) freshTypeName("?$") else freshTypeName("_$")
val t = atPos(start)(Ident(pname))
val bounds = typeBounds()
val param = atPos(t.pos union bounds.pos) { makeSyntheticTypeParam(pname, bounds) }
Expand Down Expand Up @@ -1996,8 +1995,9 @@ self =>
def argType(): Tree = {
val start = in.offset
if (isWildcardType) {
val scala3Wildcard = isScala3WildcardType
in.nextToken()
if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start)
if (in.token == SUBTYPE || in.token == SUPERTYPE) wildcardType(start, scala3Wildcard)
else atPos(start) { Bind(tpnme.WILDCARD, EmptyTree) }
} else
typ() match {
Expand Down Expand Up @@ -2364,7 +2364,7 @@ self =>
val vds = new ListBuffer[List[ValDef]]
val start = in.offset
def paramClause(): List[ValDef] = if (in.token == RPAREN) Nil else {
val implicitmod =
val implicitmod =
if (in.token == IMPLICIT) {
if (implicitOffset == -1) { implicitOffset = in.offset ; implicitSection = vds.length }
else if (warnAt == -1) warnAt = in.offset
Expand Down
11 changes: 11 additions & 0 deletions test/files/neg/wildcards-future.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
wildcards-future.scala:7: error: type mismatch;
found : Map[_$1,_$2] where type _$2 >: Null, type _$1 <: AnyRef
required: Map[String,String]
underscores : Map[String, String] // error wildcard variables starting with `_`
^
wildcards-future.scala:9: error: type mismatch;
found : Map[?$1,?$2] where type ?$2 >: Null, type ?$1 <: AnyRef
required: Map[String,String]
qmarks : Map[String, String] // error – wildcard variables should start with `?` to differentiate from the old syntax
^
two errors found
11 changes: 11 additions & 0 deletions test/files/neg/wildcards-future.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// scalac: -Xsource:3
//
object Test {
val underscores: Map[_ <: AnyRef, _ >: Null] = Map()
val qmarks: Map[? <: AnyRef, ? >: Null] = Map()

underscores : Map[String, String] // error wildcard variables starting with `_`

qmarks : Map[String, String] // error – wildcard variables should start with `?` to differentiate from the old syntax
// (and have a mildly more readable error...)
}

0 comments on commit ac638c2

Please sign in to comment.