Skip to content

Commit 35c01fe

Browse files
committed
Fix #4863: support @compileTimeOnly
1 parent 25a3773 commit 35c01fe

File tree

6 files changed

+58
-10
lines changed

6 files changed

+58
-10
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ object Annotations {
3838

3939
def sameAnnotation(that: Annotation)(implicit ctx: Context): Boolean =
4040
symbol == that.symbol && tree.sameTree(that.tree)
41+
42+
def stringArg(index: Int)(implicit ctx: Context) = argumentConstant(index) map (_.stringValue)
43+
def intArg(index: Int)(implicit ctx: Context) = argumentConstant(index) map (_.intValue)
44+
def booleanArg(index: Int)(implicit ctx: Context) = argumentConstant(index) map (_.booleanValue)
4145
}
4246

4347
case class ConcreteAnnotation(t: Tree) extends Annotation {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,8 @@ class Definitions {
855855
def TransientParamAnnot(implicit ctx: Context): ClassSymbol = TransientParamAnnotType.symbol.asClass
856856
lazy val SwitchAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.switch")
857857
def SwitchAnnot(implicit ctx: Context): ClassSymbol = SwitchAnnotType.symbol.asClass
858+
lazy val CompileTimeOnlyAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.compileTimeOnly")
859+
def CompileTimeOnlyAnnot(implicit ctx: Context): ClassSymbol = CompileTimeOnlyAnnotType.symbol.asClass
858860
lazy val ThrowsAnnotType: TypeRef = ctx.requiredClassRef("scala.throws")
859861
def ThrowsAnnot(implicit ctx: Context): ClassSymbol = ThrowsAnnotType.symbol.asClass
860862
lazy val TransientAnnotType: TypeRef = ctx.requiredClassRef("scala.transient")

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -837,6 +837,17 @@ object SymDenotations {
837837
this.exists && (test(symbol) || allOverriddenSymbols.exists(test))
838838
}
839839

840+
/** Should reference to the symbol disappear after typer?
841+
*
842+
* Used in inlining and macros to enforce invariants.
843+
*/
844+
def isCompileTimeOnly(implicit ctx: Context): Boolean =
845+
hasAnnotation(defn.CompileTimeOnlyAnnot)
846+
847+
/** Get the message associated with @compileTimeOnly annotation */
848+
def compileTimeOnlyMessage(implicit ctx: Context): Option[String] =
849+
getAnnotation(defn.CompileTimeOnlyAnnot) flatMap (_ stringArg 0)
850+
840851
// ------ access to related symbols ---------------------------------
841852

842853
/* Modules and module classes are represented as follows:

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

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -833,16 +833,15 @@ object RefChecks {
833833
case _ =>
834834
}
835835
}
836-
/* (Not enabled yet)
837-
* See an explanation of compileTimeOnly in its scaladoc at scala.annotation.compileTimeOnly.
838-
*
839-
if (sym.isCompileTimeOnly) {
840-
def defaultMsg =
841-
sm"""Reference to ${sym.fullLocationString} should not have survived past type checking,
842-
|it should have been processed and eliminated during expansion of an enclosing macro."""
843-
// The getOrElse part should never happen, it's just here as a backstop.
844-
ctx.error(sym.compileTimeOnlyMessage getOrElse defaultMsg, pos)
845-
}*/
836+
837+
if (sym.isCompileTimeOnly && !sym.owner.isInlineMethod) {
838+
def defaultMsg: String =
839+
em"""Reference to ${sym.show} should not have survived past type checking,
840+
|it should have been processed and eliminated during expansion of an enclosing macro."""
841+
// The getOrElse part should never happen, it's just here as a backstop.
842+
val msg = sym.compileTimeOnlyMessage.getOrElse(defaultMsg)
843+
ctx.error(msg, pos)
844+
}
846845
}
847846

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

tests/neg/i4863.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.annotation.compileTimeOnly
2+
3+
sealed trait Nat
4+
case class S(n: Nat) extends Nat
5+
case object Z extends Nat
6+
7+
inline def pred(n: Nat) = inline n match {
8+
case S(m) => m
9+
case Z =>
10+
@compileTimeOnly("n cannot be Z") val res = ???
11+
res
12+
}
13+
14+
class Test {
15+
pred(Z) // error
16+
}

tests/pos/i4863.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import scala.annotation.compileTimeOnly
2+
3+
sealed trait Nat
4+
case class S(n: Nat) extends Nat
5+
case object Z extends Nat
6+
7+
inline def pred(n: Nat) = inline n match {
8+
case S(m) => m
9+
case Z =>
10+
@compileTimeOnly("n cannot be Z") val res = ???
11+
res
12+
}
13+
14+
class Test {
15+
pred(S(Z))
16+
}

0 commit comments

Comments
 (0)