diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index f667fb938927..d5fc2cb29caf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -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) } diff --git a/compiler/test-resources/type-printer/hkClass b/compiler/test-resources/type-printer/hkClass index fe9539dc919a..cb1e4a0ce637 100644 --- a/compiler/test-resources/type-printer/hkClass +++ b/compiler/test-resources/type-printer/hkClass @@ -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)) diff --git a/tests/neg/type-qmark.check b/tests/neg/type-qmark.check new file mode 100644 index 000000000000..c85a114afc1b --- /dev/null +++ b/tests/neg/type-qmark.check @@ -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 diff --git a/tests/neg/type-qmark.scala b/tests/neg/type-qmark.scala new file mode 100644 index 000000000000..03eebd69d60a --- /dev/null +++ b/tests/neg/type-qmark.scala @@ -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 +}