diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Macros.scala | 11 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 27 |
2 files changed, 24 insertions, 14 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Macros.scala b/src/compiler/scala/tools/nsc/typechecker/Macros.scala index b7e0eaef2b..62a0e08aad 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Macros.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Macros.scala @@ -185,16 +185,7 @@ trait Macros { self: Analyzer => import typer.context if (macroDebug) println("typechecking macro def %s at %s".format(ddef.symbol, ddef.pos)) - typer.checkFeature(ddef.pos, MacrosFeature) - - // [Eugene to Martin] todo. copy/pasted this from checkFeature, because don't know a better way - // this is necessary to prevent macros from typechecking/expanding when they are not enabled - // `checkFeature` call alone is not enough, because it merely posts validation callback to unit.toCheck - def hasImport = inferImplicit(EmptyTree: Tree, MacrosFeature.tpe, true, false, typer.context) != SearchFailure - val nestedOwners = MacrosFeature.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse - val featureName = (nestedOwners map (_.name + ".")).mkString + MacrosFeature.name - def hasOption = settings.language.value contains featureName - if (!hasImport && !hasOption) { + if (!typer.checkFeature(ddef.pos, MacrosFeature, immediate = true)) { ddef.symbol setFlag IS_ERROR return EmptyTree } diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 0541f85f31..043e826d32 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -733,15 +733,27 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { } } - def checkFeature(pos: Position, featureTrait: Symbol, construct: => String = "") = - if (!isPastTyper) { + /** Check whether feature given by `featureTrait` is enabled. + * If it is not, issue an error or a warning depending on whether the feature is required. + * @param construct A string expression that is substituted for "#" in the feature description string + * @param immediate When set, feature check is run immediately, otherwise it is run + * at the end of the typechecking run for the enclosing unit. This + * is done to avoid potential cyclic reference errors by implicits + * that are forced too early. + * @return if feature check is run immediately: true if feature is enabled, false otherwise + * if feature check is delayed or suppressed because we are past typer: true + */ + def checkFeature(pos: Position, featureTrait: Symbol, construct: => String = "", immediate: Boolean = false): Boolean = + if (isPastTyper) true + else { val nestedOwners = featureTrait.owner.ownerChain.takeWhile(_ != languageFeatureModule.moduleClass).reverse val featureName = (nestedOwners map (_.name + ".")).mkString + featureTrait.name - unit.toCheck += { () => + def action(): Boolean = { def hasImport = inferImplicit(EmptyTree: Tree, featureTrait.tpe, true, false, context) != SearchFailure def hasOption = settings.language.value contains featureName - if (!hasImport && !hasOption) { + val OK = hasImport || hasOption + if (!OK) { val Some(AnnotationInfo(_, List(Literal(Constant(featureDesc: String)), Literal(Constant(required: Boolean))), _)) = featureTrait getAnnotation LanguageFeatureAnnot val req = if (required) "needs to" else "should" @@ -757,6 +769,13 @@ trait Typers extends Modes with Adaptations with PatMatVirtualiser { if (required) unit.error(pos, msg) else currentRun.featureWarnings.warn(pos, msg) } + OK + } + if (immediate) { + action() + } else { + unit.toCheck += action + true } } |