Skip to content

Disallow ? as a type name #8735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2321,10 +2321,20 @@ class Typer extends Namer
val typer1 = localTyper(sym)
typer1.typedDefDef(tree, sym)(using ctx.localContext(tree, sym).setTyper(typer1))
case tree: untpd.TypeDef =>
if (tree.isClassDef)
typedClassDef(tree, sym.asClass)(using ctx.localContext(tree, sym))
else
typedTypeDef(tree, sym)(using ctx.localContext(tree, sym).setNewScope)
// separate method to keep dispatching method `typedNamed` short which might help the JIT
def typedTypeOrClassDef: Tree =
if tree.name eq tpnme.? then
val addendum = if sym.owner.is(TypeParam)
then ", use `_` to denote a higher-kinded type parameter"
else ""
val namePos = tree.sourcePos.withSpan(tree.nameSpan)
ctx.errorOrMigrationWarning(s"`?` is not a valid type name$addendum", namePos)
if tree.isClassDef then
typedClassDef(tree, sym.asClass)(using ctx.localContext(tree, sym))
else
typedTypeDef(tree, sym)(using ctx.localContext(tree, sym).setNewScope)

typedTypeOrClassDef
case tree: untpd.Labeled => typedLabeled(tree)
case _ => typedUnadapted(desugar(tree), pt, locked)
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/test-resources/type-printer/hkClass
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
scala> case class Foo[M[?]](x: M[Int])
scala> case class Foo[M[_]](x: M[Int])
// defined case class Foo
scala> Foo(Option(1))
val res0: Foo[Option] = Foo(Some(1))
60 changes: 60 additions & 0 deletions tests/neg/type-qmark.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
-- Error: tests/neg/type-qmark.scala:1:10 ------------------------------------------------------------------------------
1 |class Foo[?] // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:2:12 ------------------------------------------------------------------------------
2 |class Bar[M[?]] // error
| ^
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
-- Error: tests/neg/type-qmark.scala:13:7 ------------------------------------------------------------------------------
13 | case ?() // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:16:8 ------------------------------------------------------------------------------
16 | class ? { val x = 1 } // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:19:8 ------------------------------------------------------------------------------
19 | trait ? // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:22:7 ------------------------------------------------------------------------------
22 | type ? = Int // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:25:7 ------------------------------------------------------------------------------
25 | enum ? { // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:31:8 ------------------------------------------------------------------------------
31 | given ?[T] as Foo[T] {} // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:3:8 -------------------------------------------------------------------------------
3 |def foo[?] = {} // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:4:10 ------------------------------------------------------------------------------
4 |def bar[M[?]] = {} // error
| ^
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
-- Error: tests/neg/type-qmark.scala:6:7 -------------------------------------------------------------------------------
6 |type A[?] = Int // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:7:10 ------------------------------------------------------------------------------
7 |type B = [?] =>> Int // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:8:10 ------------------------------------------------------------------------------
8 |type C = [?] => Int => Int // error
| ^
| `?` is not a valid type name
-- Error: tests/neg/type-qmark.scala:9:12 ------------------------------------------------------------------------------
9 |type D = [X[?]] =>> Int // error
| ^
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
-- Error: tests/neg/type-qmark.scala:10:12 -----------------------------------------------------------------------------
10 |type E = [X[?]] => Int => Int // error
| ^
| `?` is not a valid type name, use `_` to denote a higher-kinded type parameter
32 changes: 32 additions & 0 deletions tests/neg/type-qmark.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Foo[?] // error
class Bar[M[?]] // error
def foo[?] = {} // error
def bar[M[?]] = {} // error

type A[?] = Int // error
type B = [?] =>> Int // error
type C = [?] => Int => Int // error
type D = [X[?]] =>> Int // error
type E = [X[?]] => Int => Int // error

enum F {
case ?() // error
}
object G {
class ? { val x = 1 } // error
}
object H {
trait ? // error
}
object I {
type ? = Int // error
}
object J {
enum ? { // error
case X
}
}
object K {
class Foo[T]
given ?[T] as Foo[T] {} // error
}