Skip to content

Commit 85a53dd

Browse files
Merge pull request #6424 from dotty-staging/fix-#6419
Fix #6419: Support @compileTimeOnly
2 parents a3e2921 + 41f79c7 commit 85a53dd

File tree

11 files changed

+56
-20
lines changed

11 files changed

+56
-20
lines changed

compiler/src/dotty/tools/dotc/core/Definitions.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ class Definitions {
858858
lazy val TransientParamAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.constructorOnly")
859859
def TransientParamAnnot(implicit ctx: Context): ClassSymbol = TransientParamAnnotType.symbol.asClass
860860
lazy val CompileTimeOnlyAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.compileTimeOnly")
861-
def CompileTimeOnlyParamAnnot(implicit ctx: Context): ClassSymbol = CompileTimeOnlyAnnotType.symbol.asClass
861+
def CompileTimeOnlyAnnot(implicit ctx: Context): ClassSymbol = CompileTimeOnlyAnnotType.symbol.asClass
862862
lazy val SwitchAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.switch")
863863
def SwitchAnnot(implicit ctx: Context): ClassSymbol = SwitchAnnotType.symbol.asClass
864864
lazy val ThrowsAnnotType: TypeRef = ctx.requiredClassRef("scala.throws")

compiler/src/dotty/tools/dotc/transform/Erasure.scala

+13-2
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,19 @@ object Erasure {
326326
}
327327

328328
private def checkNotErased(tree: Tree)(implicit ctx: Context): tree.type = {
329-
if (isErased(tree) && !ctx.mode.is(Mode.Type))
330-
ctx.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.sourcePos)
329+
if (!ctx.mode.is(Mode.Type)) {
330+
if (isErased(tree))
331+
ctx.error(em"${tree.symbol} is declared as erased, but is in fact used", tree.sourcePos)
332+
tree.symbol.getAnnotation(defn.CompileTimeOnlyAnnot) match {
333+
case Some(annot) =>
334+
def defaultMsg =
335+
s"""Reference to ${tree.symbol.showLocated} should not have survived,
336+
|it should have been processed and eliminated during expansion of an enclosing macro or term erasure."""
337+
val message = annot.argumentConstant(0).fold(defaultMsg)(_.stringValue)
338+
ctx.error(message, tree.sourcePos)
339+
case _ => // OK
340+
}
341+
}
331342
tree
332343
}
333344

compiler/src/dotty/tools/dotc/transform/PostTyper.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
170170
private object dropInlines extends TreeMap {
171171
override def transform(tree: Tree)(implicit ctx: Context): Tree = tree match {
172172
case Inlined(call, _, _) =>
173-
cpy.Inlined(tree)(call, Nil, Typed(ref(defn.Predef_undefined), TypeTree(tree.tpe)))
173+
cpy.Inlined(tree)(call, Nil, Typed(ref(defn.Predef_undefined), TypeTree(tree.tpe)).withSpan(tree.span))
174174
case _ => super.transform(tree)
175175
}
176176
}

compiler/src/dotty/tools/dotc/typer/Checking.scala

-2
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,6 @@ object Checking {
401401
if (!sym.is(Deferred))
402402
fail(NativeMembersMayNotHaveImplementation(sym))
403403
}
404-
if (sym.hasAnnotation(defn.CompileTimeOnlyParamAnnot))
405-
ctx.migrationWarning("`@compileTimeOnly(msg)` will be replaced by `scala.compiletime.error(msg)`", sym.sourcePos)
406404
else if (sym.is(Deferred, butNot = Param) && !sym.isType && !sym.isSelfSym) {
407405
if (!sym.owner.isClass || sym.owner.is(Module) || sym.owner.isAnonymousClass)
408406
fail(OnlyClassesCanHaveDeclaredButUndefinedMembers(sym))

compiler/src/dotty/tools/dotc/typer/RefChecks.scala

-10
Original file line numberDiff line numberDiff line change
@@ -822,16 +822,6 @@ object RefChecks {
822822
case _ =>
823823
}
824824
}
825-
/* (Not enabled yet)
826-
* See an explanation of compileTimeOnly in its scaladoc at scala.annotation.compileTimeOnly.
827-
*
828-
if (sym.isCompileTimeOnly) {
829-
def defaultMsg =
830-
sm"""Reference to ${sym.fullLocationString} should not have survived past type checking,
831-
|it should have been processed and eliminated during expansion of an enclosing macro."""
832-
// The getOrElse part should never happen, it's just here as a backstop.
833-
ctx.error(sym.compileTimeOnlyMessage getOrElse defaultMsg, pos)
834-
}*/
835825
}
836826

837827
/** Check that a deprecated val or def does not override a

compiler/test/dotty/tools/dotc/CompilationTests.scala

+1-2
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,7 @@ class CompilationTests extends ParallelTesting {
178178
"tests/neg-custom-args/toplevel-samesource/S.scala",
179179
"tests/neg-custom-args/toplevel-samesource/nested/S.scala"),
180180
defaultOptions),
181-
compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes),
182-
compileFile("tests/neg-custom-args/i6312.scala", defaultOptions and "-Xfatal-warnings" and "-migration")
181+
compileFile("tests/neg-custom-args/i6300.scala", allowDeepSubtypes)
183182
).checkExpectedErrors()
184183
}
185184

library/src-3.x/scala/runtime/DynamicTuple.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ object DynamicTuple {
8383
def dynamic_*: [This <: Tuple, H] (self: Tuple, x: H): H *: This = {
8484
type Result = H *: This
8585
(self: Any) match {
86-
case Unit =>
86+
case () =>
8787
Tuple1(x).asInstanceOf[Result]
8888
case self: Tuple1[_] =>
8989
Tuple2(x, self._1).asInstanceOf[Result]

tests/neg/i6419.scala

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait A {
2+
@scala.annotation.compileTimeOnly("oops") def f: Int
3+
}
4+
5+
class B extends A {
6+
def f = 0
7+
}
8+
9+
object App {
10+
(new B).f
11+
(new B: A).f // error
12+
}

tests/neg/i6419b.scala

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
trait A {
2+
inline def f: Int = scala.compiletime.error("oops")
3+
}
4+
5+
class B extends A {
6+
override def f = 0
7+
}
8+
9+
object App {
10+
(new B).f
11+
(new B: A).f // error
12+
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
class Foo {
22
inline def foo: Unit = {
3-
@scala.annotation.compileTimeOnly("some message") val res = ??? // error
3+
@scala.annotation.compileTimeOnly("some message") val res = ???
44
res
55
}
66
}

tests/pos/i6419.scala

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class Foo {
2+
inline def foo: Unit = {
3+
@scala.annotation.compileTimeOnly("some message") val res = ???
4+
res
5+
}
6+
7+
inline def bar: Unit = {
8+
foo
9+
}
10+
11+
erased def baz: Unit = {
12+
foo
13+
}
14+
}

0 commit comments

Comments
 (0)