Skip to content

Commit 57c9308

Browse files
authored
Merge pull request #6610 from dotty-staging/change-wildcards
Use `?` for wildcards
2 parents 44d68de + 3db1f14 commit 57c9308

File tree

8 files changed

+70
-1
lines changed

8 files changed

+70
-1
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ class ScalaSettings extends Settings.SettingGroup {
125125
val YshowSuppressedErrors: Setting[Boolean] = BooleanSetting("-Yshow-suppressed-errors", "Also show follow-on errors and warnings that are normally suppressed.")
126126
val YdetailedStats: Setting[Boolean] = BooleanSetting("-Ydetailed-stats", "show detailed internal compiler stats (needs Stats.enabled to be set to true).")
127127
val Yheartbeat: Setting[Boolean] = BooleanSetting("-Yheartbeat", "show heartbeat stack trace of compiler operations (needs Stats.enabled to be set to true).")
128+
val YkindProjector: Setting[Boolean] = BooleanSetting("-Ykind-projector", "allow `*` as wildcard to be compatible with kind projector")
128129
val YprintPos: Setting[Boolean] = BooleanSetting("-Yprint-pos", "show tree positions.")
129130
val YprintPosSyms: Setting[Boolean] = BooleanSetting("-Yprint-pos-syms", "show symbol definitions positions.")
130131
val YnoDeepSubtypes: Setting[Boolean] = BooleanSetting("-Yno-deep-subtypes", "throw an exception on deep subtyping call stacks.")

compiler/src/dotty/tools/dotc/core/StdNames.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ object StdNames {
315315
val _21 : N = "_21"
316316
val _22 : N = "_22"
317317

318+
val * : N = "*"
319+
val ? : N = "?"
318320
val ??? : N = "???"
319321

320322
val genericWrapArray: N = "genericWrapArray"

compiler/src/dotty/tools/dotc/parsing/Parsers.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,9 +1069,21 @@ object Parsers {
10691069
SingletonTypeTree(literal(negOffset = start))
10701070
}
10711071
else if (in.token == USCORE) {
1072+
if (ctx.settings.strict.value) {
1073+
deprecationWarning(em"`_` is deprecated for wildcard arguments of types: use `?` instead")
1074+
patch(source, Span(in.offset, in.offset + 1), "?")
1075+
}
10721076
val start = in.skipToken()
10731077
typeBounds().withSpan(Span(start, in.lastOffset, start))
10741078
}
1079+
else if (isIdent(nme.?)) {
1080+
val start = in.skipToken()
1081+
typeBounds().withSpan(Span(start, in.lastOffset, start))
1082+
}
1083+
else if (isIdent(nme.*) && ctx.settings.YkindProjector.value) {
1084+
syntaxError("`*` placeholders are not implemented yet")
1085+
typeIdent()
1086+
}
10751087
else if (isSplice)
10761088
splice(isType = true)
10771089
else path(thisOK = false, handleSingletonType) match {

compiler/test/dotty/tools/dotc/CompilationTests.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ class CompilationTests extends ParallelTesting {
181181
defaultOptions),
182182
compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes),
183183
compileFile("tests/neg-custom-args/infix.scala", defaultOptions.and("-strict", "-deprecation", "-Xfatal-warnings")),
184-
compileFile("tests/neg-custom-args/missing-alpha.scala", defaultOptions.and("-strict", "-deprecation", "-Xfatal-warnings"))
184+
compileFile("tests/neg-custom-args/missing-alpha.scala", defaultOptions.and("-strict", "-deprecation", "-Xfatal-warnings")),
185+
compileFile("tests/neg-custom-args/wildcards.scala", defaultOptions.and("-strict", "-deprecation", "-Xfatal-warnings"))
185186
).checkExpectedErrors()
186187
}
187188

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
layout: doc-page
3+
title: Wildcard Arguments in Types
4+
---
5+
6+
The syntax of wildcard arguments in types has changed from `_` to `?`. Example:
7+
```scala
8+
List[?]
9+
Map[? <: AnyRef, ? >: Null]
10+
```
11+
12+
### Motivation
13+
14+
We would like to use the underscore syntax `_` to stand for an anonymous type parameter, aligning it with its meaning in
15+
value parameter lists. So, just as `f(_)` is a shorthand for the lambda `x => f(x)`, in the future `C[_]` will be a shorthand
16+
for the type lambda `[X] =>> C[X]`. This makes higher-kinded types easier to use. It also removes the wart that, used as a type
17+
parameter, `F[_]` means `F` is a type constructor whereas used as a type, `F[_]` means it is a wildcard (i.e. existential) type.
18+
In the future, `F[_]` will mean the same thing, no matter where it is used.
19+
20+
We pick `?` as a replacement syntax for wildcard types, since it aligns with Java's syntax.
21+
22+
### Migration Strategy
23+
24+
The migration to the new scheme is complicated, in particular since the [kind projector](https://github.com/typelevel/kind-projector])
25+
compiler plugin still uses the reverse convention, with `?` meaning parameter placeholder instead of wildcard. Fortunately, kind projector has added `*` as an alternative syntax for `?`.
26+
27+
A step-by-step migration is made possible with the following measures:
28+
29+
1. In Scala 3.0, both `_` and `?` are legal names for wildcards.
30+
2. In Scala 3.1, `_` is deprecated in favor of `?` as a name for a wildcard. A `-rewrite` option is
31+
available to rewrite one to the other.
32+
3. In Scala 3.2, the meaning of `_` changes from wildcard to placeholder for type parameter.
33+
4. The Scala 3.1 behavior is already available today under the `-strict` setting.
34+
35+
To smooth the transition for codebases that use kind-projector, we adopt the following measures under the command line
36+
option `-Ykind-projector`:
37+
38+
1. In Scala 3.0, `*` is available as a type parameter placeholder.
39+
2. In Scala 3.2, `*` is deprecated in favor of `_`. A `-rewrite` option is
40+
available to rewrite one to the other.
41+
3. In Scala 3.3, `*` is removed again, and all type parameter placeholders will be expressed with `_`.
42+
43+
These rules make it possible to cross build between Scala 2 using the kind projector plugin and Scala 3.0 - 3.2 using option `-Ykind-projector`.

docs/sidebar.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ sidebar:
107107
url: docs/reference/changed-features/structural-types.html
108108
- title: Operators
109109
url: docs/reference/changed-features/operators.html
110+
- title: Wildcard Types
111+
url: docs/reference/changed-features/wildcards.html
110112
- title: Type Checking
111113
url: docs/reference/changed-features/type-checking.html
112114
- title: Type Inference

tests/neg-custom-args/wildcards.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test {
2+
val xs: List[_] = List(1, 2, 3) // error
3+
val ys: Map[_ <: AnyRef, _ >: Null] = Map() // error // error
4+
}

tests/pos/wildcards.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object Test {
2+
val xs: List[?] = List(1, 2, 3)
3+
val ys: Map[? <: AnyRef, ? >: Null] = Map()
4+
}

0 commit comments

Comments
 (0)