Skip to content

Commit ce37ae4

Browse files
xeno-byadriaanm
authored andcommitted
blackbox and whitebox macros
This is the first commit in the series. This commit only: 1) Splits Context into BlackboxContext and WhiteboxContext 2) Splits Macro into BlackboxMacro and WhiteboxMacro 3) Introduces the isBundle property in the macro impl binding Here we just teach the compiler that macros can now be blackbox and whitebox, without actually imposing any restrictions on blackbox macros. These restrictions will come in subsequent commits. For description and documentation of the blackbox/whitebox separation see the official macro guide at the scaladoc website: http://docs.scala-lang.org/overviews/macros/blackbox-whitebox.html Some infrastructure work to make evolving macros easier: compile partest-extras with quick so they can use latest library/reflect/...
1 parent beed168 commit ce37ae4

File tree

246 files changed

+788
-619
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

246 files changed

+788
-619
lines changed

build.xml

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,13 +1406,6 @@ TODO:
14061406
<target name="quick.swing" depends="quick.actors, quick.lib" if="has.java6">
14071407
<staged-build with="locker" stage="quick" project="swing"/> </target>
14081408

1409-
<target name="quick.partest-extras"
1410-
depends="quick.comp">
1411-
<!-- compile compiler-specific parts of partest -->
1412-
<staged-build with="starr" stage="quick" project="partest-extras" />
1413-
<staged-build with="starr" stage="quick" project="partest-javaagent" />
1414-
</target>
1415-
14161409

14171410
<target name="quick.plugins" depends="quick.comp">
14181411
<staged-uptodate stage="quick" project="continuations-plugin">
@@ -1504,10 +1497,14 @@ TODO:
15041497
<taskdef resource="scala/tools/ant/antlib.xml" classpathref="scaladoc.classpath"/>
15051498
</target>
15061499

1507-
<target name="pack.partest-extras" depends="quick.partest-extras">
1508-
<staged-pack project="partest-extras"/>
1509-
<staged-pack project="partest-javaagent"
1510-
manifest="${src.dir}/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF"/>
1500+
<target name="pack.partest-extras" depends="quick.comp">
1501+
<!-- compile compiler-specific parts of partest -->
1502+
<staged-build with="quick" stage="quick" project="partest-extras" />
1503+
<staged-build with="quick" stage="quick" project="partest-javaagent" />
1504+
1505+
<staged-pack project="partest-extras"/>
1506+
<staged-pack project="partest-javaagent"
1507+
manifest="${src.dir}/partest-javaagent/scala/tools/partest/javaagent/MANIFEST.MF"/>
15111508
</target>
15121509

15131510
<target name="pack.bin" depends="pack.core, pack.modules, pack.partest-extras">

src/compiler/scala/reflect/macros/compiler/Errors.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ trait Errors extends Traces {
3333

3434
def MacroBundleNonStaticError() = implRefError("macro bundles must be static")
3535

36-
def MacroBundleWrongShapeError() = implRefError("macro bundles must be monomorphic traits extending scala.reflect.macros.Macro and not implementing its `val c: Context` member")
36+
def MacroBundleWrongShapeError() = implRefError("macro bundles must be monomorphic traits extending either BlackboxMacro or WhiteboxMacro and not implementing their `val c: BlackboxContext/WhiteboxContext` member")
3737

3838
// compatibility errors
3939

src/compiler/scala/reflect/macros/compiler/Resolvers.scala

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ trait Resolvers {
1515
private val runDefinitions = currentRun.runDefinitions
1616
import runDefinitions.{Predef_???, _}
1717

18-
/** Determines the type of context implied by the macro def.
19-
*/
20-
val ctxTpe = MacroContextClass.tpe
21-
2218
/** Resolves a macro impl reference provided in the right-hand side of the given macro definition.
2319
*
2420
* Acceptable shapes of the right-hand side:
@@ -44,22 +40,23 @@ trait Resolvers {
4440
}
4541

4642
val untypedImplRef = typer.silent(_.typedTypeConstructor(maybeBundleRef)) match {
47-
case SilentResultValue(result) if result.tpe.baseClasses.contains(MacroClass) =>
43+
case SilentResultValue(result) if mightBeMacroBundleType(result.tpe) =>
4844
val bundleProto = result.tpe.typeSymbol
4945
val bundlePkg = bundleProto.enclosingPackageClass
5046
if (!isMacroBundleProtoType(bundleProto.tpe)) MacroBundleWrongShapeError()
5147
if (!bundleProto.owner.isStaticOwner) MacroBundleNonStaticError()
5248

5349
// synthesize the bundle, i.e. given a static `trait Foo extends Macro { def expand = ... } `
54-
// create a top-level definition `class Foo$Bundle(val c: Context) extends Foo` in a package next to `Foo`
50+
// create a top-level definition `class Foo$Bundle(val c: BlackboxContext/WhiteboxContext) extends Foo` in a package next to `Foo`
5551
val bundlePid = gen.mkUnattributedRef(bundlePkg)
5652
val bundlePrefix =
5753
if (bundlePkg == EmptyPackageClass) bundleProto.fullName('$')
5854
else bundleProto.fullName('$').substring(bundlePkg.fullName('$').length + 1)
5955
val bundleName = TypeName(bundlePrefix + tpnme.MACRO_BUNDLE_SUFFIX)
6056
val existingBundle = bundleProto.enclosingPackageClass.info.decl(bundleName)
6157
if (!currentRun.compiles(existingBundle)) {
62-
def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(ctxTpe), EmptyTree)
58+
val contextType = if (isBlackboxMacroBundleType(bundleProto.tpe)) BlackboxContextClass.tpe else WhiteboxContextClass.tpe
59+
def mkContextValDef(flags: Long) = ValDef(Modifiers(flags), nme.c, TypeTree(contextType), EmptyTree)
6360
val contextField = mkContextValDef(PARAMACCESSOR)
6461
val contextParam = mkContextValDef(PARAM | PARAMACCESSOR)
6562
val bundleCtor = DefDef(Modifiers(), nme.CONSTRUCTOR, Nil, List(List(contextParam)), TypeTree(), Block(List(pendingSuperCall), Literal(Constant(()))))
@@ -88,12 +85,13 @@ trait Resolvers {
8885
// lazy val (isImplBundle, macroImplOwner, macroImpl, macroImplTargs) =
8986
private lazy val dissectedMacroImplRef =
9087
macroImplRef match {
91-
case MacroImplReference(isBundle, owner, meth, targs) => (isBundle, owner, meth, targs)
88+
case MacroImplReference(isBundle, isBlackbox, owner, meth, targs) => (isBundle, isBlackbox, owner, meth, targs)
9289
case _ => MacroImplReferenceWrongShapeError()
9390
}
9491
lazy val isImplBundle = dissectedMacroImplRef._1
9592
lazy val isImplMethod = !isImplBundle
96-
lazy val macroImplOwner = dissectedMacroImplRef._2
97-
lazy val macroImpl = dissectedMacroImplRef._3
98-
lazy val targs = dissectedMacroImplRef._4
93+
lazy val isImplBlackbox = dissectedMacroImplRef._2
94+
lazy val macroImplOwner = dissectedMacroImplRef._3
95+
lazy val macroImpl = dissectedMacroImplRef._4
96+
lazy val targs = dissectedMacroImplRef._5
9997
}

src/compiler/scala/reflect/macros/compiler/Validators.scala

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ trait Validators {
4949
map2(aparamss.flatten, rparamss.flatten)((aparam, rparam) => {
5050
if (aparam.name != rparam.name && !rparam.isSynthetic) MacroImplParamNameMismatchError(aparam, rparam)
5151
if (isRepeated(aparam) ^ isRepeated(rparam)) MacroImplVarargMismatchError(aparam, rparam)
52-
val aparamtpe = aparam.tpe.dealias match {
53-
case RefinedType(List(tpe), Scope(sym)) if tpe =:= ctxTpe && sym.allOverriddenSymbols.contains(MacroContextPrefixType) => tpe
52+
val aparamtpe = aparam.tpe match {
53+
case MacroContextType(tpe) => tpe
5454
case tpe => tpe
5555
}
5656
checkMacroImplParamTypeMismatch(atpeToRtpe(aparamtpe), rparam)
@@ -93,20 +93,20 @@ trait Validators {
9393
*
9494
* For the following macro impl:
9595
* def fooBar[T: c.WeakTypeTag]
96-
* (c: scala.reflect.macros.Context)
96+
* (c: scala.reflect.macros.BlackboxContext)
9797
* (xs: c.Expr[List[T]])
9898
* : c.Expr[T] = ...
9999
*
100100
* This function will return:
101-
* (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]])c.Expr[T]
101+
* (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[List[T]])c.Expr[T]
102102
*
103103
* Note that type tag evidence parameters are not included into the result.
104104
* Type tag context bounds for macro impl tparams are optional.
105105
* Therefore compatibility checks ignore such parameters, and we don't need to bother about them here.
106106
*
107107
* This method cannot be reduced to just macroImpl.info, because macro implementations might
108-
* come in different shapes. If the implementation is an apply method of a Macro-compatible object,
109-
* then it won't have (c: Context) in its parameters, but will rather refer to Macro.c.
108+
* come in different shapes. If the implementation is an apply method of a BlackboxMacro/WhiteboxMacro-compatible object,
109+
* then it won't have (c: BlackboxContext/WhiteboxContext) in its parameters, but will rather refer to BlackboxMacro/WhiteboxMacro.c.
110110
*
111111
* @param macroImpl The macro implementation symbol
112112
*/
@@ -123,7 +123,8 @@ trait Validators {
123123
* def foo[T](xs: List[T]): T = macro fooBar
124124
*
125125
* This function will return:
126-
* (c: scala.reflect.macros.Context)(xs: c.Expr[List[T]])c.Expr[T]
126+
* (c: scala.reflect.macros.BlackboxContext)(xs: c.Expr[List[T]])c.Expr[T] or
127+
* (c: scala.reflect.macros.WhiteboxContext)(xs: c.Expr[List[T]])c.Expr[T]
127128
*
128129
* Note that type tag evidence parameters are not included into the result.
129130
* Type tag context bounds for macro impl tparams are optional.
@@ -145,6 +146,7 @@ trait Validators {
145146
// had to move method's body to an object because of the recursive dependencies between sigma and param
146147
object SigGenerator {
147148
val cache = scala.collection.mutable.Map[Symbol, Symbol]()
149+
val ctxTpe = if (isImplBlackbox) BlackboxContextClass.tpe else WhiteboxContextClass.tpe
148150
val ctxPrefix =
149151
if (isImplMethod) singleType(NoPrefix, makeParam(nme.macroContext, macroDdef.pos, ctxTpe, SYNTHETIC))
150152
else singleType(ThisType(macroImpl.owner), macroImpl.owner.tpe.member(nme.c))

src/compiler/scala/reflect/macros/contexts/Context.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ package contexts
33

44
import scala.tools.nsc.Global
55

6-
abstract class Context extends scala.reflect.macros.Context
6+
abstract class Context extends scala.reflect.macros.BlackboxContext
7+
with scala.reflect.macros.WhiteboxContext
78
with Aliases
89
with Enclosures
910
with Names

src/compiler/scala/reflect/macros/runtime/MacroRuntimes.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ trait MacroRuntimes extends JavaReflectionRuntimes with ScalaReflectionRuntimes
4545
type MacroRuntime = MacroArgs => Any
4646
class MacroRuntimeResolver(val macroDef: Symbol) extends JavaReflectionResolvers
4747
with ScalaReflectionResolvers {
48-
val binding = loadMacroImplBinding(macroDef)
48+
val binding = loadMacroImplBinding(macroDef).get
4949
val isBundle = binding.isBundle
5050
val className = binding.className
5151
val methName = binding.methName

src/compiler/scala/reflect/macros/util/Helpers.scala

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ trait Helpers {
2727
import runDefinitions._
2828

2929
val MacroContextUniverse = definitions.MacroContextUniverse
30-
val treeInfo.MacroImplReference(isBundle, _, macroImpl, _) = macroImplRef
30+
val treeInfo.MacroImplReference(isBundle, _, _, macroImpl, _) = macroImplRef
3131
val paramss = macroImpl.paramss
3232
val ContextParam = paramss match {
33-
case Nil | _ :+ Nil => NoSymbol // no implicit parameters in the signature => nothing to do
34-
case _ if isBundle => macroImpl.owner.tpe member nme.c
35-
case (cparam :: _) :: _ if cparam.tpe <:< MacroContextClass.tpe => cparam
36-
case _ => NoSymbol // no context parameter in the signature => nothing to do
33+
case Nil | _ :+ Nil => NoSymbol // no implicit parameters in the signature => nothing to do
34+
case _ if isBundle => macroImpl.owner.tpe member nme.c
35+
case (cparam :: _) :: _ if isMacroContextType(cparam.tpe) => cparam
36+
case _ => NoSymbol // no context parameter in the signature => nothing to do
3737
}
3838
def transformTag(param: Symbol): Symbol = param.tpe.dealias match {
3939
case TypeRef(SingleType(SingleType(_, ContextParam), MacroContextUniverse), WeakTypeTagClass, targ :: Nil) => transform(param, targ.typeSymbol)

src/compiler/scala/tools/nsc/typechecker/ContextErrors.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,9 @@ trait ContextErrors {
527527
def TooManyArgsPatternError(fun: Tree) =
528528
NormalTypeError(fun, "too many arguments for unapply pattern, maximum = "+definitions.MaxTupleArity)
529529

530+
def BlackboxExtractorExpansion(fun: Tree) =
531+
NormalTypeError(fun, "extractor macros can only be whitebox")
532+
530533
def WrongShapeExtractorExpansion(fun: Tree) =
531534
NormalTypeError(fun, "extractor macros can only expand into extractor calls")
532535

src/compiler/scala/tools/nsc/typechecker/Implicits.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1147,7 +1147,7 @@ trait Implicits {
11471147
gen.mkAttributedThis(thisSym)
11481148
case _ =>
11491149
// if `pre` is not a PDT, e.g. if someone wrote
1150-
// implicitly[scala.reflect.macros.Context#TypeTag[Int]]
1150+
// implicitly[scala.reflect.macros.BlackboxContext#TypeTag[Int]]
11511151
// then we need to fail, because we don't know the prefix to use during type reification
11521152
// upd. we also need to fail silently, because this is a very common situation
11531153
// e.g. quite often we're searching for BaseUniverse#TypeTag, e.g. for a type tag in any universe

0 commit comments

Comments
 (0)