From ac638c278fd088c89e97d39eecb665bacdefa0bf Mon Sep 17 00:00:00 2001 From: Kai Date: Thu, 6 May 2021 12:36:54 +0100 Subject: [PATCH] Differentiate Scala 2 and Scala 3 wildcard identifier names 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 --- .../scala/tools/nsc/ast/parser/Parsers.scala | 22 +++++++++---------- test/files/neg/wildcards-future.check | 11 ++++++++++ test/files/neg/wildcards-future.scala | 11 ++++++++++ 3 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 test/files/neg/wildcards-future.check create mode 100644 test/files/neg/wildcards-future.scala diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index a724652a1aa1..5532d9328354 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -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 @@ -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) @@ -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) } @@ -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 { @@ -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 diff --git a/test/files/neg/wildcards-future.check b/test/files/neg/wildcards-future.check new file mode 100644 index 000000000000..a5b4b23520f3 --- /dev/null +++ b/test/files/neg/wildcards-future.check @@ -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 diff --git a/test/files/neg/wildcards-future.scala b/test/files/neg/wildcards-future.scala new file mode 100644 index 000000000000..54b7675813e7 --- /dev/null +++ b/test/files/neg/wildcards-future.scala @@ -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...) +}