Skip to content

Commit 30aa58d

Browse files
committed
Disallow ? as a type name
Now that we use `?` for wildcards, we should treat it more like a keyword for types and not allow it as a type name to avoid confusion.
1 parent 755a81f commit 30aa58d

File tree

4 files changed

+107
-5
lines changed

4 files changed

+107
-5
lines changed

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2321,10 +2321,20 @@ class Typer extends Namer
23212321
val typer1 = localTyper(sym)
23222322
typer1.typedDefDef(tree, sym)(using ctx.localContext(tree, sym).setTyper(typer1))
23232323
case tree: untpd.TypeDef =>
2324-
if (tree.isClassDef)
2325-
typedClassDef(tree, sym.asClass)(using ctx.localContext(tree, sym))
2326-
else
2327-
typedTypeDef(tree, sym)(using ctx.localContext(tree, sym).setNewScope)
2324+
// separate method to keep dispatching method `typedNamed` short which might help the JIT
2325+
def typedTypeOrClassDef: Tree =
2326+
if tree.name eq tpnme.? then
2327+
val addendum = if sym.owner.is(TypeParam)
2328+
then ", use `_` to denote a higher-kinded type parameter"
2329+
else ""
2330+
val namePos = tree.sourcePos.withSpan(tree.nameSpan)
2331+
ctx.errorOrMigrationWarning(s"`?` is not a valid type name$addendum", namePos)
2332+
if tree.isClassDef then
2333+
typedClassDef(tree, sym.asClass)(using ctx.localContext(tree, sym))
2334+
else
2335+
typedTypeDef(tree, sym)(using ctx.localContext(tree, sym).setNewScope)
2336+
2337+
typedTypeOrClassDef
23282338
case tree: untpd.Labeled => typedLabeled(tree)
23292339
case _ => typedUnadapted(desugar(tree), pt, locked)
23302340
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
scala> case class Foo[M[?]](x: M[Int])
1+
scala> case class Foo[M[_]](x: M[Int])
22
// defined case class Foo
33
scala> Foo(Option(1))
44
val res0: Foo[Option] = Foo(Some(1))

tests/neg/type-qmark.check

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
-- Error: tests/neg/type-qmark.scala:1:10 ------------------------------------------------------------------------------
2+
1 |class Foo[?] // error
3+
| ^
4+
| `?` is not a valid type name
5+
-- Error: tests/neg/type-qmark.scala:2:12 ------------------------------------------------------------------------------
6+
2 |class Bar[M[?]] // error
7+
| ^
8+
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
9+
-- Error: tests/neg/type-qmark.scala:13:7 ------------------------------------------------------------------------------
10+
13 | case ?() // error
11+
| ^
12+
| `?` is not a valid type name
13+
-- Error: tests/neg/type-qmark.scala:16:8 ------------------------------------------------------------------------------
14+
16 | class ? { val x = 1 } // error
15+
| ^
16+
| `?` is not a valid type name
17+
-- Error: tests/neg/type-qmark.scala:19:8 ------------------------------------------------------------------------------
18+
19 | trait ? // error
19+
| ^
20+
| `?` is not a valid type name
21+
-- Error: tests/neg/type-qmark.scala:22:7 ------------------------------------------------------------------------------
22+
22 | type ? = Int // error
23+
| ^
24+
| `?` is not a valid type name
25+
-- Error: tests/neg/type-qmark.scala:25:7 ------------------------------------------------------------------------------
26+
25 | enum ? { // error
27+
| ^
28+
| `?` is not a valid type name
29+
-- Error: tests/neg/type-qmark.scala:31:8 ------------------------------------------------------------------------------
30+
31 | given ?[T] as Foo[T] {} // error
31+
| ^
32+
| `?` is not a valid type name
33+
-- Error: tests/neg/type-qmark.scala:3:8 -------------------------------------------------------------------------------
34+
3 |def foo[?] = {} // error
35+
| ^
36+
| `?` is not a valid type name
37+
-- Error: tests/neg/type-qmark.scala:4:10 ------------------------------------------------------------------------------
38+
4 |def bar[M[?]] = {} // error
39+
| ^
40+
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
41+
-- Error: tests/neg/type-qmark.scala:6:7 -------------------------------------------------------------------------------
42+
6 |type A[?] = Int // error
43+
| ^
44+
| `?` is not a valid type name
45+
-- Error: tests/neg/type-qmark.scala:7:10 ------------------------------------------------------------------------------
46+
7 |type B = [?] =>> Int // error
47+
| ^
48+
| `?` is not a valid type name
49+
-- Error: tests/neg/type-qmark.scala:8:10 ------------------------------------------------------------------------------
50+
8 |type C = [?] => Int => Int // error
51+
| ^
52+
| `?` is not a valid type name
53+
-- Error: tests/neg/type-qmark.scala:9:12 ------------------------------------------------------------------------------
54+
9 |type D = [X[?]] =>> Int // error
55+
| ^
56+
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
57+
-- Error: tests/neg/type-qmark.scala:10:12 -----------------------------------------------------------------------------
58+
10 |type E = [X[?]] => Int => Int // error
59+
| ^
60+
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter

tests/neg/type-qmark.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
class Foo[?] // error
2+
class Bar[M[?]] // error
3+
def foo[?] = {} // error
4+
def bar[M[?]] = {} // error
5+
6+
type A[?] = Int // error
7+
type B = [?] =>> Int // error
8+
type C = [?] => Int => Int // error
9+
type D = [X[?]] =>> Int // error
10+
type E = [X[?]] => Int => Int // error
11+
12+
enum F {
13+
case ?() // error
14+
}
15+
object G {
16+
class ? { val x = 1 } // error
17+
}
18+
object H {
19+
trait ? // error
20+
}
21+
object I {
22+
type ? = Int // error
23+
}
24+
object J {
25+
enum ? { // error
26+
case X
27+
}
28+
}
29+
object K {
30+
class Foo[T]
31+
given ?[T] as Foo[T] {} // error
32+
}

0 commit comments

Comments
 (0)