Skip to content

Commit

Permalink
Fix scala#4863: support @compileTimeOnly
Browse files Browse the repository at this point in the history
  • Loading branch information
liufengyun committed Apr 15, 2019
1 parent 25a3773 commit 35c01fe
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 10 deletions.
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Annotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ object Annotations {

def sameAnnotation(that: Annotation)(implicit ctx: Context): Boolean =
symbol == that.symbol && tree.sameTree(that.tree)

def stringArg(index: Int)(implicit ctx: Context) = argumentConstant(index) map (_.stringValue)
def intArg(index: Int)(implicit ctx: Context) = argumentConstant(index) map (_.intValue)
def booleanArg(index: Int)(implicit ctx: Context) = argumentConstant(index) map (_.booleanValue)
}

case class ConcreteAnnotation(t: Tree) extends Annotation {
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -855,6 +855,8 @@ class Definitions {
def TransientParamAnnot(implicit ctx: Context): ClassSymbol = TransientParamAnnotType.symbol.asClass
lazy val SwitchAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.switch")
def SwitchAnnot(implicit ctx: Context): ClassSymbol = SwitchAnnotType.symbol.asClass
lazy val CompileTimeOnlyAnnotType: TypeRef = ctx.requiredClassRef("scala.annotation.compileTimeOnly")
def CompileTimeOnlyAnnot(implicit ctx: Context): ClassSymbol = CompileTimeOnlyAnnotType.symbol.asClass
lazy val ThrowsAnnotType: TypeRef = ctx.requiredClassRef("scala.throws")
def ThrowsAnnot(implicit ctx: Context): ClassSymbol = ThrowsAnnotType.symbol.asClass
lazy val TransientAnnotType: TypeRef = ctx.requiredClassRef("scala.transient")
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dotty/tools/dotc/core/SymDenotations.scala
Original file line number Diff line number Diff line change
Expand Up @@ -837,6 +837,17 @@ object SymDenotations {
this.exists && (test(symbol) || allOverriddenSymbols.exists(test))
}

/** Should reference to the symbol disappear after typer?
*
* Used in inlining and macros to enforce invariants.
*/
def isCompileTimeOnly(implicit ctx: Context): Boolean =
hasAnnotation(defn.CompileTimeOnlyAnnot)

/** Get the message associated with @compileTimeOnly annotation */
def compileTimeOnlyMessage(implicit ctx: Context): Option[String] =
getAnnotation(defn.CompileTimeOnlyAnnot) flatMap (_ stringArg 0)

// ------ access to related symbols ---------------------------------

/* Modules and module classes are represented as follows:
Expand Down
19 changes: 9 additions & 10 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -833,16 +833,15 @@ 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)
}*/

if (sym.isCompileTimeOnly && !sym.owner.isInlineMethod) {
def defaultMsg: String =
em"""Reference to ${sym.show} 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.
val msg = sym.compileTimeOnlyMessage.getOrElse(defaultMsg)
ctx.error(msg, pos)
}
}

/** Check that a deprecated val or def does not override a
Expand Down
16 changes: 16 additions & 0 deletions tests/neg/i4863.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import scala.annotation.compileTimeOnly

sealed trait Nat
case class S(n: Nat) extends Nat
case object Z extends Nat

inline def pred(n: Nat) = inline n match {
case S(m) => m
case Z =>
@compileTimeOnly("n cannot be Z") val res = ???
res
}

class Test {
pred(Z) // error
}
16 changes: 16 additions & 0 deletions tests/pos/i4863.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import scala.annotation.compileTimeOnly

sealed trait Nat
case class S(n: Nat) extends Nat
case object Z extends Nat

inline def pred(n: Nat) = inline n match {
case S(m) => m
case Z =>
@compileTimeOnly("n cannot be Z") val res = ???
res
}

class Test {
pred(S(Z))
}

0 comments on commit 35c01fe

Please sign in to comment.