diff options
author | Jason Zaugg <jzaugg@gmail.com> | 2012-11-06 22:23:09 +0100 |
---|---|---|
committer | Jason Zaugg <jzaugg@gmail.com> | 2012-11-06 22:31:50 +0100 |
commit | 6902da3168c02448387edc000dedfe97ef5f7cd9 (patch) | |
tree | 4110e85872ce34f79c73bef7e5b6a2e3130b0a8f | |
parent | 3b68b45a200087104a1ac2de7c4b86635023fd4d (diff) | |
download | scala-6902da3168c02448387edc000dedfe97ef5f7cd9.tar.gz scala-6902da3168c02448387edc000dedfe97ef5f7cd9.tar.bz2 scala-6902da3168c02448387edc000dedfe97ef5f7cd9.zip |
SI-6539 Annotation for methods unfit for post-typer ASTs
Motivated by the `.value` method in the SBT task-syntax branch,
which should only be called within the context of the argument
to a setting initialization macro.
The facility is akin to a fatal deprecation.
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 6 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Definitions.scala | 1 | ||||
-rw-r--r-- | src/reflect/scala/reflect/internal/Symbols.scala | 3 | ||||
-rw-r--r-- | src/reflect/scala/reflect/macros/compileTimeOnly.scala | 16 | ||||
-rw-r--r-- | test/files/neg/t6539.check | 10 | ||||
-rw-r--r-- | test/files/neg/t6539/Macro_1.scala | 10 | ||||
-rw-r--r-- | test/files/neg/t6539/Test_2.scala | 6 |
7 files changed, 52 insertions, 0 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index c1dc91dbfc..726c8d3b24 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -1376,6 +1376,11 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans ) } + private def checkCompileTimeOnly(sym: Symbol, pos: Position) = { + if (sym.isCompileTimeOnly) + unit.error(pos, s"reference to ${sym.fullLocationString} should not survive typechecking: ${sym.compileTimeOnlyMessage.get}") + } + private def lessAccessible(otherSym: Symbol, memberSym: Symbol): Boolean = ( (otherSym != NoSymbol) && !otherSym.isProtected @@ -1562,6 +1567,7 @@ abstract class RefChecks extends InfoTransform with scala.reflect.internal.trans checkDeprecated(sym, tree.pos) if (settings.Xmigration28.value) checkMigration(sym, tree.pos) + checkCompileTimeOnly(sym, tree.pos) if (sym eq NoSymbol) { unit.warning(tree.pos, "Select node has NoSymbol! " + tree + " / " + tree.tpe) diff --git a/src/reflect/scala/reflect/internal/Definitions.scala b/src/reflect/scala/reflect/internal/Definitions.scala index e24971a309..4c7694c319 100644 --- a/src/reflect/scala/reflect/internal/Definitions.scala +++ b/src/reflect/scala/reflect/internal/Definitions.scala @@ -944,6 +944,7 @@ trait Definitions extends api.StandardDefinitions { lazy val BeanPropertyAttr = requiredClass[scala.beans.BeanProperty] lazy val BooleanBeanPropertyAttr = requiredClass[scala.beans.BooleanBeanProperty] lazy val CloneableAttr = requiredClass[scala.annotation.cloneable] + lazy val CompileTimeOnlyAttr = requiredClass[scala.reflect.macros.compileTimeOnly] lazy val DeprecatedAttr = requiredClass[scala.deprecated] lazy val DeprecatedNameAttr = requiredClass[scala.deprecatedName] lazy val DeprecatedInheritanceAttr = requiredClass[scala.deprecatedInheritance] diff --git a/src/reflect/scala/reflect/internal/Symbols.scala b/src/reflect/scala/reflect/internal/Symbols.scala index 7cb9a0e105..7a0f5f2caf 100644 --- a/src/reflect/scala/reflect/internal/Symbols.scala +++ b/src/reflect/scala/reflect/internal/Symbols.scala @@ -743,6 +743,9 @@ trait Symbols extends api.Symbols { self: SymbolTable => def elisionLevel = getAnnotation(ElidableMethodClass) flatMap { _.intArg(0) } def implicitNotFoundMsg = getAnnotation(ImplicitNotFoundClass) flatMap { _.stringArg(0) } + def isCompileTimeOnly = hasAnnotation(CompileTimeOnlyAttr) + def compileTimeOnlyMessage = getAnnotation(CompileTimeOnlyAttr) flatMap (_ stringArg 0) + /** Is this symbol an accessor method for outer? */ final def isOuterAccessor = { hasFlag(STABLE | ARTIFACT) && diff --git a/src/reflect/scala/reflect/macros/compileTimeOnly.scala b/src/reflect/scala/reflect/macros/compileTimeOnly.scala new file mode 100644 index 0000000000..4018e7db71 --- /dev/null +++ b/src/reflect/scala/reflect/macros/compileTimeOnly.scala @@ -0,0 +1,16 @@ +package scala.reflect +package macros + +import scala.annotation.meta._ + +/** + * An annotation that designates a member should not be referred to after + * type checking (which includes macro expansion); it must only be used in + * the arguments of some other macro that will eliminate it from the AST. + * + * @param message the error message to print during compilation if a reference remains + * after type checking + * @since 2.10.0 + */ +@getter @setter @beanGetter @beanSetter +final class compileTimeOnly(message: String = "") extends scala.annotation.StaticAnnotation diff --git a/test/files/neg/t6539.check b/test/files/neg/t6539.check new file mode 100644 index 0000000000..a5d5a7244d --- /dev/null +++ b/test/files/neg/t6539.check @@ -0,0 +1,10 @@ +Test_2.scala:2: error: reference to method cto in object M should not survive typechecking: cto may only be used as an argument to m + M.cto // error + ^ +Test_2.scala:3: error: reference to method cto in object M should not survive typechecking: cto may only be used as an argument to m + M.m(M.cto, ()) // error + ^ +Test_2.scala:5: error: reference to method cto in object M should not survive typechecking: cto may only be used as an argument to m + M.cto // error + ^ +three errors found diff --git a/test/files/neg/t6539/Macro_1.scala b/test/files/neg/t6539/Macro_1.scala new file mode 100644 index 0000000000..69bd53fe07 --- /dev/null +++ b/test/files/neg/t6539/Macro_1.scala @@ -0,0 +1,10 @@ +import language.experimental.macros +import reflect.macros.Context + +object M { + def m(a: Any, b: Any): Any = macro mImpl + def mImpl(c: Context)(a: c.Expr[Any], b: c.Expr[Any]) = a + + @reflect.macros.compileTimeOnly("cto may only be used as an argument to m") + def cto = 0 +} diff --git a/test/files/neg/t6539/Test_2.scala b/test/files/neg/t6539/Test_2.scala new file mode 100644 index 0000000000..1569c79788 --- /dev/null +++ b/test/files/neg/t6539/Test_2.scala @@ -0,0 +1,6 @@ +object Test { + M.cto // error + M.m(M.cto, ()) // error + M.m((), M.cto) // okay + M.cto // error +}
\ No newline at end of file |