summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker/Namers.scala
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2011-11-28 11:01:12 +0000
committerMartin Odersky <odersky@gmail.com>2011-11-28 11:01:12 +0000
commit311d813910a2ec590b11b84c28fac2ae6e086270 (patch)
tree4a35454e77a8d09d822a7b7c3126b10c7c3861bb /src/compiler/scala/tools/nsc/typechecker/Namers.scala
parent0bea2ab5f6b211a83bbf14ea46fe57b8163c6334 (diff)
downloadscala-311d813910a2ec590b11b84c28fac2ae6e086270.tar.gz
scala-311d813910a2ec590b11b84c28fac2ae6e086270.tar.bz2
scala-311d813910a2ec590b11b84c28fac2ae6e086270.zip
Experimental version of macro definitions.
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker/Namers.scala')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala56
1 files changed, 41 insertions, 15 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index d503371f5d..4c85830311 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -59,7 +59,7 @@ trait Namers extends MethodSynthesis {
// is stored in this map. The map is cleared lazily, i.e. when the new symbol
// is created with the same name, the old one (if present) is wiped out, or the
// entry is deleted when it is used and no longer needed.
- private val caseClassOfModuleClass = perRunCaches.newWeakMap[Symbol, WeakReference[ClassDef]]()
+ private val classOfModuleClass = perRunCaches.newWeakMap[Symbol, WeakReference[ClassDef]]()
// Default getters of constructors are added to the companion object in the
// typeCompleter of the constructor (methodSig). To compute the signature,
@@ -421,8 +421,8 @@ trait Namers extends MethodSynthesis {
* class definition tree.
* @return the companion object symbol.
*/
- def ensureCompanionObject(tree: ClassDef, creator: => Tree): Symbol = {
- val m = companionModuleOf(tree.symbol, context)
+ def ensureCompanionObject(cdef: ClassDef, creator: ClassDef => Tree = companionModuleDef(_)): Symbol = {
+ val m = companionModuleOf(cdef.symbol, context)
// @luc: not sure why "currentRun.compiles(m)" is needed, things breaks
// otherwise. documentation welcome.
//
@@ -435,8 +435,16 @@ trait Namers extends MethodSynthesis {
// Map(class Foo -> Nil)
// What exactly this implies and whether this is a sensible way to
// enforce it, I don't know.
+ //
+ // @martin: currentRun.compiles is needed because we might have a stale
+ // companion object from another run in scope. In that case we should still
+ // overwrite the object. I.e.
+ // Compile run #1: object Foo { ... }
+ // Compile run #2: case class Foo ...
+ // The object Foo is still in scope, but because it is not compiled in current run
+ // it should be ditched and a new one created.
if (m != NoSymbol && currentRun.compiles(m)) m
- else enterSyntheticSym(creator)
+ else enterSyntheticSym(creator(cdef))
}
private def checkSelectors(tree: Import): Unit = {
@@ -599,6 +607,11 @@ trait Namers extends MethodSynthesis {
enterCopyMethodOrGetter(tree, tparams)
else
sym setInfo completerOf(tree, tparams)
+
+ if (mods hasFlag MACRO) {
+ if (!(sym.owner.isClass && sym.owner.isStatic))
+ context.error(tree.pos, "macro definition must appear in globally accessible class")
+ }
}
def enterClassDef(tree: ClassDef) {
@@ -610,17 +623,25 @@ trait Namers extends MethodSynthesis {
if (treeInfo.firstConstructorArgs(impl.body).size > MaxFunctionArity)
context.error(tree.pos, "Implementation restriction: case classes cannot have more than " + MaxFunctionArity + " parameters.")
- val m = ensureCompanionObject(tree, caseModuleDef(tree))
- caseClassOfModuleClass(m.moduleClass) = new WeakReference(tree)
+ val m = ensureCompanionObject(tree, caseModuleDef)
+ classOfModuleClass(m.moduleClass) = new WeakReference(tree)
}
val hasDefault = impl.body exists {
case DefDef(_, nme.CONSTRUCTOR, _, vparamss, _, _) => listutil.mexists(vparamss)(_.mods.hasDefault)
case _ => false
}
if (hasDefault) {
- val m = ensureCompanionObject(tree, companionModuleDef(tree))
+ val m = ensureCompanionObject(tree)
classAndNamerOfModule(m) = (tree, null)
}
+ val hasMacro = impl.body exists {
+ case DefDef(mods, _, _, _, _, _) => mods hasFlag MACRO
+ case _ => false
+ }
+ if (hasMacro) {
+ val m = ensureCompanionObject(tree)
+ classOfModuleClass(m.moduleClass) = new WeakReference(tree)
+ }
val owner = tree.symbol.owner
if (owner.isPackageObjectClass) {
context.unit.warning(tree.pos,
@@ -816,25 +837,27 @@ trait Namers extends MethodSynthesis {
// add apply and unapply methods to companion objects of case classes,
// unless they exist already; here, "clazz" is the module class
if (clazz.isModuleClass) {
- Namers.this.caseClassOfModuleClass get clazz foreach { cdefRef =>
+ Namers.this.classOfModuleClass get clazz foreach { cdefRef =>
val cdef = cdefRef()
- addApplyUnapply(cdef, templateNamer)
- caseClassOfModuleClass -= clazz
+ if (cdef.mods.isCase) addApplyUnapply(cdef, templateNamer)
+ addMacroMethods(cdef.impl, templateNamer)
+ classOfModuleClass -= clazz
}
+ addMacroMethods(templ, templateNamer)
}
// add the copy method to case classes; this needs to be done here, not in SyntheticMethods, because
// the namer phase must traverse this copy method to create default getters for its parameters.
// here, clazz is the ClassSymbol of the case class (not the module).
// @check: this seems to work only if the type completer of the class runs before the one of the
- // module class: the one from the module class removes the entry from caseClassOfModuleClass (see above).
+ // module class: the one from the module class removes the entry from classOfModuleClass (see above).
if (clazz.isClass && !clazz.hasModuleFlag) {
val modClass = companionModuleOf(clazz, context).moduleClass
- Namers.this.caseClassOfModuleClass get modClass map { cdefRef =>
+ Namers.this.classOfModuleClass get modClass map { cdefRef =>
val cdef = cdefRef()
def hasCopy(decls: Scope) = (decls lookup nme.copy) != NoSymbol
- if (!hasCopy(decls) &&
+ if (cdef.mods.isCase && !hasCopy(decls) &&
!parents.exists(p => hasCopy(p.typeSymbol.info.decls)) &&
!parents.flatMap(_.baseClasses).distinct.exists(bc => hasCopy(bc.info.decls)))
addCopyMethod(cdef, templateNamer)
@@ -977,13 +1000,16 @@ trait Namers extends MethodSynthesis {
thisMethodType({
val rt = (
- if (tpt.isEmpty) {
+ if (!tpt.isEmpty) {
+ typer.typedType(tpt).tpe
+ } else if (meth.isMacro) {
+ AnyClass.tpe
+ } else {
// replace deSkolemized symbols with skolemized ones
// (for resultPt computed by looking at overridden symbol, right?)
val pt = resultPt.substSym(tparamSyms, tparams map (_.symbol))
assignTypeToTree(ddef, typer, pt)
}
- else typer.typedType(tpt).tpe
)
// #2382: return type of default getters are always @uncheckedVariance
if (meth.hasDefaultFlag)