From f4ff6e374aa4112b240177e810887fb9f5ecbde3 Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Wed, 14 Feb 2024 09:16:23 +0100 Subject: [PATCH] Only allow erased parameters in erased definitions So far, we do not have any use case for them. We could enable them in a later version. The current implementation does not handle correctly the non-erased arguments to erased definitions. These should always be evaluated, but in some cases we can dorp them by mistake. --- .../tools/dotc/transform/PostTyper.scala | 7 ++++ tests/coverage/run/erased/test.scala | 2 +- .../coverage/run/erased/test.scoverage.check | 42 +++++++++---------- tests/neg/erased-1.scala | 17 ++------ tests/neg/erased-2.scala | 21 ++-------- tests/neg/erased-3.scala | 21 ++-------- tests/neg/erased-args-lifted.scala | 2 +- tests/neg/erased-params.scala | 12 ++++++ tests/pos/i7741.scala | 2 +- 9 files changed, 54 insertions(+), 72 deletions(-) create mode 100644 tests/neg/erased-params.scala diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index cc175fc5c222..60e4075e8674 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -553,7 +553,14 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => report.error("classes that extend MacroAnnotation must not be inner/local classes", sym.srcPos) private def checkErasedDef(tree: ValOrDefDef)(using Context): Unit = + def checkOnlyErasedParams(): Unit = tree match + case tree: DefDef => + for params <- tree.paramss; param <- params if !param.symbol.isType && !param.symbol.is(Erased) do + report.error("erased definition can only have erased parameters", param.srcPos) + case _ => + if tree.symbol.is(Erased, butNot = Macro) then + checkOnlyErasedParams() val tpe = tree.rhs.tpe if tpe.derivesFrom(defn.NothingClass) then report.error("`erased` definition cannot be implemented with en expression of type Nothing", tree.srcPos) diff --git a/tests/coverage/run/erased/test.scala b/tests/coverage/run/erased/test.scala index 15a067e9ed50..6645020cac80 100644 --- a/tests/coverage/run/erased/test.scala +++ b/tests/coverage/run/erased/test.scala @@ -2,7 +2,7 @@ import scala.language.experimental.erasedDefinitions erased def parameterless: String = "y" -erased def e(x: String): String = "x" +erased def e(erased x: String): String = "x" def foo(erased a: String)(b: String): String = println(s"foo(a)($b)") b diff --git a/tests/coverage/run/erased/test.scoverage.check b/tests/coverage/run/erased/test.scoverage.check index dedf5689c490..aed6338099aa 100644 --- a/tests/coverage/run/erased/test.scoverage.check +++ b/tests/coverage/run/erased/test.scoverage.check @@ -25,8 +25,8 @@ test$package Object .test$package foo -181 -203 +188 +210 7 println Apply @@ -42,8 +42,8 @@ test$package Object .test$package foo -189 -202 +196 +209 7 s Apply @@ -59,8 +59,8 @@ test$package Object .test$package foo -132 139 +146 6 foo DefDef @@ -76,8 +76,8 @@ test$package Object .test$package identity -245 -269 +252 +276 11 println Apply @@ -93,8 +93,8 @@ test$package Object .test$package identity -253 -268 +260 +275 11 s Apply @@ -110,8 +110,8 @@ test$package Object .test$package identity -209 -221 +216 +228 10 identity DefDef @@ -127,8 +127,8 @@ test$package Object .test$package Test -300 -323 +307 +330 16 foo Apply @@ -144,8 +144,8 @@ test$package Object .test$package Test -326 -342 +333 +349 17 foo Apply @@ -161,8 +161,8 @@ test$package Object .test$package Test -345 -374 +352 +381 18 foo Apply @@ -178,8 +178,8 @@ test$package Object .test$package Test -357 -373 +364 +380 18 identity Apply @@ -195,8 +195,8 @@ test$package Object .test$package Test -275 -289 +282 +296 15 Test DefDef diff --git a/tests/neg/erased-1.scala b/tests/neg/erased-1.scala index 62a1024e80f5..deaa2a6d750e 100644 --- a/tests/neg/erased-1.scala +++ b/tests/neg/erased-1.scala @@ -12,25 +12,14 @@ object Test { }) foo1(a) // OK foo2( // error - a // error - ) - foo3( // error - a + a // Ok ) a // error } - erased def foo2(a: Int): Int = { - foo0(a) // OK - foo1(a) // OK - foo2(a) // OK - foo3(a) // OK - a // OK - } - erased def foo3(erased a: Int): Int = { + erased def foo2(erased a: Int): Int = { foo0(a) // OK foo1(a) // OK foo2(a) // OK - foo3(a) // OK a // OK } -} \ No newline at end of file +} diff --git a/tests/neg/erased-2.scala b/tests/neg/erased-2.scala index 02e4b56e11ac..3b51d9a4a40b 100644 --- a/tests/neg/erased-2.scala +++ b/tests/neg/erased-2.scala @@ -8,39 +8,26 @@ object Test { ) foo1(u) // OK foo2( // error - u // error - ) - foo3( // error - u + u // Ok ) u // error u // error } - erased def foo2(a: Int): Int = { - foo0(u) // OK - foo1(u) // OK - foo2(u) // OK - foo3(u) // OK - u // warn - u // OK - } - erased def foo3(erased a: Int): Int = { + erased def foo2(erased a: Int): Int = { foo0(u) // OK foo1(u) // OK foo2(u) // OK - foo3(u) // OK u // warn u // OK } - erased val foo4: Int = { + erased val foo3: Int = { foo0(u) // OK foo1(u) // OK foo2(u) // OK - foo3(u) // OK u // warn u // OK } erased def u: Int = 42 -} \ No newline at end of file +} diff --git a/tests/neg/erased-3.scala b/tests/neg/erased-3.scala index 5c6a31860b11..7b33794791b6 100644 --- a/tests/neg/erased-3.scala +++ b/tests/neg/erased-3.scala @@ -8,40 +8,27 @@ object Test { ) foo1(u()) // OK foo2( // error - u() // error - ) - foo3( // error - u() + u() // Ok ) u() // error u() // error } - erased def foo2(a: Int): Int = { - foo0(u()) // OK - foo1(u()) // OK - foo2(u()) // OK - foo3(u()) // OK - u() // warn - u() // OK - } - erased def foo3(erased a: Int): Int = { + erased def foo2(erased a: Int): Int = { foo0(u()) // OK foo1(u()) // OK foo2(u()) // OK - foo3(u()) // OK u() // warn u() // OK } - erased val foo4: Int = { + erased val foo3: Int = { foo0(u()) // OK foo1(u()) // OK foo2(u()) // OK - foo3(u()) // OK println() u() // warn u() // OK } erased def u(): Int = 42 -} \ No newline at end of file +} diff --git a/tests/neg/erased-args-lifted.scala b/tests/neg/erased-args-lifted.scala index 2deee749ed3d..dfa7b74ee3d4 100644 --- a/tests/neg/erased-args-lifted.scala +++ b/tests/neg/erased-args-lifted.scala @@ -2,7 +2,7 @@ object Test { def foo(a: Int)(b: Int, c: Int) = 42 - erased def bar(i: Int): Int = { + erased def bar(erased i: Int): Int = { println(1) 42 } diff --git a/tests/neg/erased-params.scala b/tests/neg/erased-params.scala new file mode 100644 index 000000000000..2315b6bdf54d --- /dev/null +++ b/tests/neg/erased-params.scala @@ -0,0 +1,12 @@ +import scala.language.experimental.erasedDefinitions + +erased def test1(x: Int): Int = x // error +erased def test2(erased x: Int): Int = x +erased def test3(erased x: Int, erased y: Int): Int = x +erased def test4(erased x: Int, y: Int): Int = x // error +erased def test5(x: Int, erased y: Int): Int = y // error +erased def test6(x: Int, y: Int): Int = y // error // error +erased def test7(erased x: Int)(erased y: Int): Int = x +erased def test8(erased x: Int)(y: Int): Int = x // error +erased def test9(x: Int)(erased y: Int): Int = y // error +erased def test10(x: Int)(y: Int): Int = y // error // error diff --git a/tests/pos/i7741.scala b/tests/pos/i7741.scala index 237616d04d2a..af9912915cc0 100644 --- a/tests/pos/i7741.scala +++ b/tests/pos/i7741.scala @@ -4,7 +4,7 @@ class A1 { @native private def a: Unit } trait A2 { - erased def i(a: Int): Int + erased def i(erased a: Int): Int } trait A3 { erased val a: Int