diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index 23fcc80d3f22..ca1755f1a847 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -370,6 +370,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => val callTrace = ref(call.symbol)(using ctx.withSource(pos.source)).withSpan(pos.span) cpy.Inlined(tree)(callTrace, transformSub(bindings), transform(expansion)(using inlineContext(tree))) case templ: Template => + Checking.checkPolyFunctionExtension(templ) withNoCheckNews(templ.parents.flatMap(newPart)) { forwardParamAccessors(templ) synthMbr.addSyntheticMembers( diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 04db7f086eec..54898329fe0e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -845,6 +845,14 @@ object Checking { def reportNoRefinements(pos: SrcPos) = report.error("PolyFunction subtypes must refine the apply method", pos) }.traverse(tree) + + /** Check that users do not extend the `PolyFunction` trait. + * We only allow compiler generated `PolyFunction`s. + */ + def checkPolyFunctionExtension(templ: Template)(using Context): Unit = + templ.parents.find(_.tpe.derivesFrom(defn.PolyFunctionClass)) match + case Some(parent) => report.error(s"`PolyFunction` marker trait is reserved for compiler generated refinements", parent.srcPos) + case None => } trait Checking { diff --git a/tests/run/erased-15.scala b/tests/neg/erased-15.scala similarity index 86% rename from tests/run/erased-15.scala rename to tests/neg/erased-15.scala index ac3adc428ffb..47073d2517bd 100644 --- a/tests/run/erased-15.scala +++ b/tests/neg/erased-15.scala @@ -12,7 +12,7 @@ object Test { } } -class Foo extends PolyFunction { +class Foo extends PolyFunction { // error def apply(erased x: Int): Int = { println("Foo.apply") 42 diff --git a/tests/neg/i10075.check b/tests/neg/i10075.check new file mode 100644 index 000000000000..6f3e9ab4334a --- /dev/null +++ b/tests/neg/i10075.check @@ -0,0 +1,32 @@ +-- Error: tests/neg/i10075.scala:8:24 ---------------------------------------------------------------------------------- +8 |trait PolyTrait extends PolyFunction // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:10:24 --------------------------------------------------------------------------------- +10 |class PolyClass extends PolyTrait { // error + | ^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:14:26 --------------------------------------------------------------------------------- +14 |object PolyObject extends PolyFunction // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:2:14 ---------------------------------------------------------------------------------- +2 |val foo = new PolyFunction { } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:3:14 ---------------------------------------------------------------------------------- +3 |val bar = new PolyFunction { def bar = 23 } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:4:14 ---------------------------------------------------------------------------------- +4 |val baz = new PolyFunction { def apply = 23 } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:5:14 ---------------------------------------------------------------------------------- +5 |val qux = new PolyFunction { def apply[T] = 47 } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements +-- Error: tests/neg/i10075.scala:6:15 ---------------------------------------------------------------------------------- +6 |val quxx = new PolyFunction { def apply[T](x: T): T = x } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements diff --git a/tests/neg/i10075.scala b/tests/neg/i10075.scala new file mode 100644 index 000000000000..e1a255ec8b54 --- /dev/null +++ b/tests/neg/i10075.scala @@ -0,0 +1,14 @@ +val poly = [T] => (x: T) => x +val foo = new PolyFunction { } // error +val bar = new PolyFunction { def bar = 23 } // error +val baz = new PolyFunction { def apply = 23 } // error +val qux = new PolyFunction { def apply[T] = 47 } // error +val quxx = new PolyFunction { def apply[T](x: T): T = x } // error + +trait PolyTrait extends PolyFunction // error + +class PolyClass extends PolyTrait { // error + def apply[T](x: T): T = x +} + +object PolyObject extends PolyFunction // error diff --git a/tests/neg/i10369.scala b/tests/neg/i10369.scala new file mode 100644 index 000000000000..703dea249d7a --- /dev/null +++ b/tests/neg/i10369.scala @@ -0,0 +1,10 @@ +type Upgrade[T] = T match + case Int => Double + case Char => String + case Boolean => Boolean + +val upgrade: [t] => t => Upgrade[t] = new PolyFunction: // error + def apply[T](x: T): Upgrade[T] = x match + case x: Int => x.toDouble + case x: Char => x.toString + case x: Boolean => !x diff --git a/tests/pos/i18302a.scala b/tests/neg/i18302a.scala similarity index 55% rename from tests/pos/i18302a.scala rename to tests/neg/i18302a.scala index c087b63543f4..dc4bc703c404 100644 --- a/tests/pos/i18302a.scala +++ b/tests/neg/i18302a.scala @@ -1,4 +1,4 @@ def test = polyFun(1) def polyFun: PolyFunction { def apply(x: Int): Int } = - new PolyFunction { def apply(x: Int): Int = x + 1 } + new PolyFunction { def apply(x: Int): Int = x + 1 } // error diff --git a/tests/neg/i18302b.check b/tests/neg/i18302b.check index 0dc3ba6c054a..624c0cc0e415 100644 --- a/tests/neg/i18302b.check +++ b/tests/neg/i18302b.check @@ -2,3 +2,7 @@ 3 |def polyFun: PolyFunction { def apply(x: Int)(y: Int): Int } = // error | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |Implementation restriction: PolyFunction apply must have exactly one parameter list and optionally type arguments. No by-name nor varags are allowed. +-- Error: tests/neg/i18302b.scala:4:6 ---------------------------------------------------------------------------------- +4 | new PolyFunction: // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements diff --git a/tests/neg/i18302b.scala b/tests/neg/i18302b.scala index 71c7992c178b..4e6379d7e8e0 100644 --- a/tests/neg/i18302b.scala +++ b/tests/neg/i18302b.scala @@ -1,5 +1,5 @@ def test = polyFun(1)(2) def polyFun: PolyFunction { def apply(x: Int)(y: Int): Int } = // error - new PolyFunction: + new PolyFunction: // error def apply(x: Int)(y: Int): Int = x + y diff --git a/tests/neg/i18302c.check b/tests/neg/i18302c.check index 4610145a30b2..67dffcfae98c 100644 --- a/tests/neg/i18302c.check +++ b/tests/neg/i18302c.check @@ -2,3 +2,7 @@ 4 |def polyFun: PolyFunction { def foo(x: Int): Int } = // error | ^^^^^^^^^^^^^^^^^^^^ | PolyFunction only supports apply method refinements +-- Error: tests/neg/i18302c.scala:5:6 ---------------------------------------------------------------------------------- +5 | new PolyFunction { def foo(x: Int): Int = x + 1 } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements diff --git a/tests/neg/i18302c.scala b/tests/neg/i18302c.scala index a5d182d7ad0c..ddf7e28e47d5 100644 --- a/tests/neg/i18302c.scala +++ b/tests/neg/i18302c.scala @@ -2,4 +2,4 @@ import scala.reflect.Selectable.reflectiveSelectable def test = polyFun.foo(1) def polyFun: PolyFunction { def foo(x: Int): Int } = // error - new PolyFunction { def foo(x: Int): Int = x + 1 } + new PolyFunction { def foo(x: Int): Int = x + 1 } // error diff --git a/tests/neg/i18302d.check b/tests/neg/i18302d.check index 976db59763c1..f052735a4db2 100644 --- a/tests/neg/i18302d.check +++ b/tests/neg/i18302d.check @@ -2,3 +2,7 @@ 1 |def polyFun: PolyFunction { def apply: Int } = // error | ^^^^^^^^^^^^^^ |Implementation restriction: PolyFunction apply must have exactly one parameter list and optionally type arguments. No by-name nor varags are allowed. +-- Error: tests/neg/i18302d.scala:2:6 ---------------------------------------------------------------------------------- +2 | new PolyFunction { def apply: Int = 1 } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements diff --git a/tests/neg/i18302d.scala b/tests/neg/i18302d.scala index a7f9a5bec286..2555bffe81aa 100644 --- a/tests/neg/i18302d.scala +++ b/tests/neg/i18302d.scala @@ -1,2 +1,2 @@ def polyFun: PolyFunction { def apply: Int } = // error - new PolyFunction { def apply: Int = 1 } + new PolyFunction { def apply: Int = 1 } // error diff --git a/tests/neg/i18302e.check b/tests/neg/i18302e.check index aae101875845..7fbe19e8213d 100644 --- a/tests/neg/i18302e.check +++ b/tests/neg/i18302e.check @@ -2,6 +2,10 @@ 1 |def polyFun: PolyFunction { } = // error | ^^^^^^^^^^^^^^^^^ | PolyFunction subtypes must refine the apply method +-- Error: tests/neg/i18302e.scala:2:6 ---------------------------------------------------------------------------------- +2 | new PolyFunction { } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements -- Error: tests/neg/i18302e.scala:4:15 --------------------------------------------------------------------------------- 4 |def polyFun(f: PolyFunction { }) = () // error | ^^^^^^^^^^^^^^^^^ diff --git a/tests/neg/i18302e.scala b/tests/neg/i18302e.scala index 1ffab2586048..80f13053e8c6 100644 --- a/tests/neg/i18302e.scala +++ b/tests/neg/i18302e.scala @@ -1,4 +1,4 @@ def polyFun: PolyFunction { } = // error - new PolyFunction { } + new PolyFunction { } // error def polyFun(f: PolyFunction { }) = () // error diff --git a/tests/neg/i18302f.check b/tests/neg/i18302f.check index df0d76c2f157..5231e894fabb 100644 --- a/tests/neg/i18302f.check +++ b/tests/neg/i18302f.check @@ -2,6 +2,10 @@ 1 |def polyFun: PolyFunction = // error | ^^^^^^^^^^^^ | PolyFunction subtypes must refine the apply method +-- Error: tests/neg/i18302f.scala:2:6 ---------------------------------------------------------------------------------- +2 | new PolyFunction { } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements -- Error: tests/neg/i18302f.scala:4:16 --------------------------------------------------------------------------------- 4 |def polyFun2(a: PolyFunction) = () // error | ^^^^^^^^^^^^ @@ -10,3 +14,7 @@ 6 |val polyFun3: PolyFunction = // error | ^^^^^^^^^^^^ | PolyFunction subtypes must refine the apply method +-- Error: tests/neg/i18302f.scala:7:6 ---------------------------------------------------------------------------------- +7 | new PolyFunction { } // error + | ^^^^^^^^^^^^ + | `PolyFunction` marker trait is reserved for compiler generated refinements diff --git a/tests/neg/i18302f.scala b/tests/neg/i18302f.scala index 2f86f0e1eb62..c62d4fdc1189 100644 --- a/tests/neg/i18302f.scala +++ b/tests/neg/i18302f.scala @@ -1,7 +1,7 @@ def polyFun: PolyFunction = // error - new PolyFunction { } + new PolyFunction { } // error def polyFun2(a: PolyFunction) = () // error val polyFun3: PolyFunction = // error - new PolyFunction { } + new PolyFunction { } // error diff --git a/tests/neg/i18302j.scala b/tests/neg/i18302j.scala index 8c63aa573c9b..1f674f953fa9 100644 --- a/tests/neg/i18302j.scala +++ b/tests/neg/i18302j.scala @@ -1,5 +1,5 @@ def polyFunByName: PolyFunction { def apply(thunk: => Int): Int } = // error - new PolyFunction { def apply(thunk: => Int): Int = 1 } + new PolyFunction { def apply(thunk: => Int): Int = 1 } // error def polyFunVarArgs: PolyFunction { def apply(args: Int*): Int } = // error - new PolyFunction { def apply(thunk: Int*): Int = 1 } + new PolyFunction { def apply(thunk: Int*): Int = 1 } // error diff --git a/tests/pos/i10369.scala b/tests/pos/i10369.scala index 8689c2833664..90261230f75b 100644 --- a/tests/pos/i10369.scala +++ b/tests/pos/i10369.scala @@ -3,12 +3,6 @@ type Upgrade[T] = T match case Char => String case Boolean => Boolean -val upgrade: [t] => t => Upgrade[t] = new PolyFunction: - def apply[T](x: T): Upgrade[T] = x match - case x: Int => x.toDouble - case x: Char => x.toString - case x: Boolean => !x - val upgrade2: [t] => t => Upgrade[t] = [t] => (x: t) => x match case x: Int => x.toDouble case x: Char => x.toString diff --git a/tests/run/erased-15.check b/tests/run/erased-15.check deleted file mode 100644 index f1880f44381b..000000000000 --- a/tests/run/erased-15.check +++ /dev/null @@ -1 +0,0 @@ -Foo.apply