From 311d813910a2ec590b11b84c28fac2ae6e086270 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 28 Nov 2011 11:01:12 +0000 Subject: Experimental version of macro definitions. --- .../scala/tools/nsc/typechecker/Namers.scala | 56 ++++++++++++++++------ 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'src/compiler/scala/tools/nsc/typechecker/Namers.scala') 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) -- cgit v1.2.3