diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 2bc6c26d0ab3..8f17da8500de 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -858,7 +858,7 @@ class Definitions { lazy val TransientParamAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.constructorOnly") def TransientParamAnnot(implicit ctx: Context): ClassSymbol = TransientParamAnnotType.symbol.asClass lazy val CompileTimeOnlyAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.compileTimeOnly") - def CompileTimeOnlyParamAnnot(implicit ctx: Context): ClassSymbol = CompileTimeOnlyAnnotType.symbol.asClass + def CompileTimeOnlyAnnot(implicit ctx: Context): ClassSymbol = CompileTimeOnlyAnnotType.symbol.asClass lazy val SwitchAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.switch") def SwitchAnnot(implicit ctx: Context): ClassSymbol = SwitchAnnotType.symbol.asClass lazy val ThrowsAnnotType: TypeRef = ctx.requiredClassRef("scala.throws") diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala index be7d2c740126..9e3435225151 100644 --- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala +++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala @@ -326,8 +326,19 @@ object Erasure { } private def checkNotErased(tree: Tree)(implicit ctx: Context): tree.type = { - if (isErased(tree) && !ctx.mode.is(Mode.Type)) - ctx.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.sourcePos) + if (!ctx.mode.is(Mode.Type)) { + if (isErased(tree)) + ctx.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.sourcePos) + tree.symbol.getAnnotation(defn.CompileTimeOnlyAnnot) match { + case Some(annot) => + def defaultMsg = + s"""Reference to ${tree.symbol.showLocated} should not have survived, + |it should have been processed and eliminated during expansion of an enclosing macro or term erasure.""" + val message = annot.argumentConstant(0).fold(defaultMsg)(_.stringValue) + ctx.error(message, tree.sourcePos) + case _ => // OK + } + } tree } diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index e69f8fc727f1..fd3110ba2d03 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -170,7 +170,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase private object dropInlines extends TreeMap { override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match { case Inlined(call, _, _) => - cpy.Inlined(tree)(call, Nil, Typed(ref(defn.Predef_undefined), TypeTree(tree.tpe))) + cpy.Inlined(tree)(call, Nil, Typed(ref(defn.Predef_undefined), TypeTree(tree.tpe)).withSpan(tree.span)) case _ => super.transform(tree) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index b85bc32e5bb8..ce6431e2bc12 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -401,8 +401,6 @@ object Checking { if (!sym.is(Deferred)) fail(NativeMembersMayNotHaveImplementation(sym)) } - if (sym.hasAnnotation(defn.CompileTimeOnlyParamAnnot)) - ctx.migrationWarning("`@compileTimeOnly(msg)` will be replaced by `scala.compiletime.error(msg)`", sym.sourcePos) else if (sym.is(Deferred, butNot = Param) && !sym.isType && !sym.isSelfSym) { if (!sym.owner.isClass || sym.owner.is(Module) || sym.owner.isAnonymousClass) fail(OnlyClassesCanHaveDeclaredButUndefinedMembers(sym)) diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 3d8d345d6a27..50ba767d7aec 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -822,16 +822,6 @@ object RefChecks { case _ => } } - /* (Not enabled yet) - * See an explanation of compileTimeOnly in its scaladoc at scala.annotation.compileTimeOnly. - * - if (sym.isCompileTimeOnly) { - def defaultMsg = - sm"""Reference to ${sym.fullLocationString} should not have survived past type checking, - |it should have been processed and eliminated during expansion of an enclosing macro.""" - // The getOrElse part should never happen, it's just here as a backstop. - ctx.error(sym.compileTimeOnlyMessage getOrElse defaultMsg, pos) - }*/ } /** Check that a deprecated val or def does not override a diff --git a/compiler/test/dotty/tools/dotc/CompilationTests.scala b/compiler/test/dotty/tools/dotc/CompilationTests.scala index d59702406dd0..4bb3ebce93b8 100644 --- a/compiler/test/dotty/tools/dotc/CompilationTests.scala +++ b/compiler/test/dotty/tools/dotc/CompilationTests.scala @@ -178,8 +178,7 @@ class CompilationTests extends ParallelTesting { "tests/neg-custom-args/toplevel-samesource/S.scala", "tests/neg-custom-args/toplevel-samesource/nested/S.scala"), defaultOptions), - compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes), - compileFile("tests/neg-custom-args/i6312.scala", defaultOptions and "-Xfatal-warnings" and "-migration") + compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes) ).checkExpectedErrors() } diff --git a/library/src-3.x/scala/runtime/DynamicTuple.scala b/library/src-3.x/scala/runtime/DynamicTuple.scala index 6560de1cf410..a3fe8055227a 100644 --- a/library/src-3.x/scala/runtime/DynamicTuple.scala +++ b/library/src-3.x/scala/runtime/DynamicTuple.scala @@ -83,7 +83,7 @@ object DynamicTuple { def dynamic_*: [This <: Tuple, H] (self: Tuple, x: H): H *: This = { type Result = H *: This (self: Any) match { - case Unit => + case () => Tuple1(x).asInstanceOf[Result] case self: Tuple1[_] => Tuple2(x, self._1).asInstanceOf[Result] diff --git a/tests/neg/i6419.scala b/tests/neg/i6419.scala new file mode 100644 index 000000000000..08ec19594e9b --- /dev/null +++ b/tests/neg/i6419.scala @@ -0,0 +1,12 @@ +trait A { + @scala.annotation.compileTimeOnly("oops") def f: Int +} + +class B extends A { + def f = 0 +} + +object App { + (new B).f + (new B: A).f // error +} diff --git a/tests/neg/i6419b.scala b/tests/neg/i6419b.scala new file mode 100644 index 000000000000..c14907e8fc2d --- /dev/null +++ b/tests/neg/i6419b.scala @@ -0,0 +1,12 @@ +trait A { + inline def f: Int = scala.compiletime.error("oops") +} + +class B extends A { + override def f = 0 +} + +object App { + (new B).f + (new B: A).f // error +} diff --git a/tests/neg-custom-args/i6312.scala b/tests/pos/i6312b.scala similarity index 90% rename from tests/neg-custom-args/i6312.scala rename to tests/pos/i6312b.scala index c80e5c246a00..8109c222a652 100644 --- a/tests/neg-custom-args/i6312.scala +++ b/tests/pos/i6312b.scala @@ -1,6 +1,6 @@ class Foo { inline def foo: Unit = { - @scala.annotation.compileTimeOnly("some message") val res = ??? // error + @scala.annotation.compileTimeOnly("some message") val res = ??? res } } diff --git a/tests/pos/i6419.scala b/tests/pos/i6419.scala new file mode 100644 index 000000000000..b398e9856dee --- /dev/null +++ b/tests/pos/i6419.scala @@ -0,0 +1,14 @@ +class Foo { + inline def foo: Unit = { + @scala.annotation.compileTimeOnly("some message") val res = ??? + res + } + + inline def bar: Unit = { + foo + } + + erased def baz: Unit = { + foo + } +}