diff options
-rw-r--r-- | src/compiler/scala/tools/nsc/Global.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala | 115 |
2 files changed, 55 insertions, 64 deletions
diff --git a/src/compiler/scala/tools/nsc/Global.scala b/src/compiler/scala/tools/nsc/Global.scala index 2845ee8e03..83f4ce438f 100644 --- a/src/compiler/scala/tools/nsc/Global.scala +++ b/src/compiler/scala/tools/nsc/Global.scala @@ -179,6 +179,10 @@ class Global(var currentSettings: Settings, var reporter: Reporter) extends Symb def inform[T](msg: String, value: T): T = returning(value)(x => inform(msg + x)) def informTime(msg: String, start: Long) = informProgress(elapsedMessage(msg, start)) + def logResult[T](msg: String)(result: T): T = { + log(msg + ": " + result) + result + } def logError(msg: String, t: Throwable): Unit = () // Over 200 closure objects are eliminated by inlining this. @inline final def log(msg: => AnyRef): Unit = diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 95a86b25c8..4972c6295a 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -35,17 +35,16 @@ trait SyntheticMethods extends ast.TreeDSL { import global._ // the global environment import definitions._ // standard classes and methods - /** Add the synthetic methods to case classes. Note that a lot of the - * complexity herein is a consequence of case classes inheriting from - * case classes, which has been deprecated as of Sep 11 2009. So when - * the opportunity for removal arises, this can be simplified. + /** Add the synthetic methods to case classes. */ def addSyntheticMethods(templ: Template, clazz: Symbol, context: Context): Template = { + import CODE._ + val localTyper = newTyper( if (reporter.hasErrors) context makeSilent false else context ) def accessorTypes = clazz.caseFieldAccessors map (_.tpe.finalResultType) - def accessorLub = global.weakLub(accessorTypes)._1 + def accessorLub = global.weakLub(accessorTypes)._1 def hasOverridingImplementation(meth: Symbol): Boolean = { val sym = clazz.info nonPrivateMember meth.name @@ -61,10 +60,13 @@ trait SyntheticMethods extends ast.TreeDSL { def newSyntheticMethod(name: Name, flags: Int, tpeCons: Symbol => Type) = { val method = clazz.newMethod(clazz.pos.focus, name.toTermName) setFlag flags - method setInfo tpeCons(method) - clazz.info.decls.enter(method) + + clazz.info.decls enter (method setInfo tpeCons(method)) } + def newTypedMethod(method: Symbol)(body: Tree): Tree = + localTyper typed { DEF(method) === body } + def makeNoArgConstructor(res: Type) = (sym: Symbol) => MethodType(Nil, res) def makeTypeConstructor(args: List[Type], res: Type) = @@ -72,16 +74,12 @@ trait SyntheticMethods extends ast.TreeDSL { def makeEqualityMethod(name: Name) = syntheticMethod(name, 0, makeTypeConstructor(List(AnyClass.tpe), BooleanClass.tpe)) - import CODE._ + def newNullaryMethod(name: TermName, tpe: Type, body: Tree) = { + val flags = if (clazz.tpe.member(name) != NoSymbol) OVERRIDE else 0 + val method = clazz.newMethod(clazz.pos.focus, name) setFlag flags - def newNullaryMethod(name: Name, tpe: Type, body: Tree) = { - val flags = if (clazz.tpe.member(name.toTermName) != NoSymbol) OVERRIDE else 0 - val method = clazz.newMethod(clazz.pos.focus, name.toTermName) setFlag flags - - method setInfo NullaryMethodType(tpe) - clazz.info.decls enter method - - typer typed (DEF(method) === body) + clazz.info.decls enter (method setInfo NullaryMethodType(tpe)) + newTypedMethod(method)(body) } def productPrefixMethod = newNullaryMethod(nme.productPrefix, StringClass.tpe, LIT(clazz.name.decode)) def productArityMethod(arity: Int) = newNullaryMethod(nme.productArity, IntClass.tpe, LIT(arity)) @@ -111,11 +109,7 @@ trait SyntheticMethods extends ast.TreeDSL { for ((sym, i) <- accs.zipWithIndex) yield CASE(LIT(i)) ==> caseFn(sym) - typer typed { - DEF(method) === { - arg MATCH { cases ::: default : _* } - } - } + newTypedMethod(method)(arg MATCH { cases ::: default : _* }) } def productElementMethod(accs: List[Symbol]): Tree = perElementMethod(accs, nme.productElement, AnyClass.tpe, x => Ident(x)) @@ -125,14 +119,12 @@ trait SyntheticMethods extends ast.TreeDSL { def moduleToStringMethod: Tree = { val method = syntheticMethod(nme.toString_, FINAL, makeNoArgConstructor(StringClass.tpe)) - typer typed { DEF(method) === LIT(clazz.name.decode) } + newTypedMethod(method)(LIT(clazz.name.decode)) } def moduleHashCodeMethod: Tree = { val method = syntheticMethod(nme.hashCode_, FINAL, makeNoArgConstructor(IntClass.tpe)) // The string being used as hashcode basis is also productPrefix. - val code = clazz.name.decode.hashCode - - typer typed { DEF(method) === LIT(code) } + newTypedMethod(method)(LIT(clazz.name.decode.hashCode)) } def forwardingMethod(name: Name, targetName: Name): Tree = { @@ -140,34 +132,25 @@ trait SyntheticMethods extends ast.TreeDSL { val paramtypes = target.tpe.paramTypes drop 1 val method = syntheticMethod(name, 0, makeTypeConstructor(paramtypes, target.tpe.resultType)) - typer typed { - DEF(method) === { - Apply(REF(target), This(clazz) :: (method ARGNAMES)) - } - } + newTypedMethod(method)(Apply(REF(target), This(clazz) :: (method ARGNAMES))) } /** The equality method for case modules: - * def equals(that: Any) = this eq that + * def equals(that: Any) = this eq that */ def equalsModuleMethod: Tree = { val method = makeEqualityMethod(nme.equals_) - val that = method ARG 0 - localTyper typed { - DEF(method) === (This(clazz) ANY_EQ that) - } + newTypedMethod(method)(This(clazz) ANY_EQ (method ARG 0)) } - /** The canEqual method for case classes. Note that if we spot - * a user-supplied equals implementation, we simply return true - * so as not to interfere. + /** The canEqual method for case classes. + * def canEqual(that: Any) = that.isInstanceOf[This] */ def canEqualMethod: Tree = { val method = makeEqualityMethod(nme.canEqual_) - val that = method ARG 0 - typer typed (DEF(method) === (that IS_OBJ clazz.tpe)) + newTypedMethod(method)((method ARG 0) IS_OBJ clazz.tpe) } /** The equality method for case classes. The argument is an Any, @@ -190,12 +173,15 @@ trait SyntheticMethods extends ast.TreeDSL { def makeTrees(acc: Symbol, cpt: Type): (Tree, Bind) = { val varName = context.unit.freshTermName(acc.name + "$") val isRepeated = isRepeatedParamType(cpt) - val binding = if (isRepeated) Star(WILD.empty) else WILD.empty + val binding = Bind( + varName, + if (isRepeated) Star(WILD.empty) else WILD.empty + ) val eqMethod: Tree = if (isRepeated) gen.mkRuntimeCall(nme.sameElements, List(Ident(varName), Ident(acc))) else (Ident(varName) DOT nme.EQ)(Ident(acc)) - (eqMethod, Bind(varName, binding)) + (eqMethod, binding) } // Creates list of parameters and a guard for each @@ -206,40 +192,41 @@ trait SyntheticMethods extends ast.TreeDSL { val that: Tree = (method ARG 0) AS clazz.tpe val canEqualOther: Symbol = clazz.info nonPrivateMember nme.canEqual_ - typer typed { - (that DOT canEqualOther)(This(clazz)) - } + typer typed { (that DOT canEqualOther)(This(clazz)) } } // Pattern is classname applied to parameters, and guards are all logical and-ed - val (guard, pat) = (AND(guards: _*), Ident(clazz.name.toTermName) APPLY params) - - localTyper typed { - DEF(method) === { - (This(clazz) ANY_EQ that) OR (that MATCH( - (CASE(pat) IF guard) ==> canEqualCheck() , - DEFAULT ==> FALSE - )) - } + val guard = AND(guards: _*) + // You might think this next line could be written + // val pat = Ident(clazz.companionModule) APPLY params + // However this prevents the compiler from bootstrapping, + // possibly due to a bug in how case classes are handled when + // read from classfiles as opposed to from source. + val pat = Ident(clazz.name.toTermName) APPLY params + + newTypedMethod(method) { + (This(clazz) ANY_EQ that) OR (that MATCH( + (CASE(pat) IF guard) ==> canEqualCheck() , + DEFAULT ==> FALSE + )) } } def newAccessorMethod(tree: Tree): Tree = tree match { case DefDef(_, _, _, _, _, rhs) => - var newAcc = tree.symbol.cloneSymbol + val newAcc = tree.symbol.cloneSymbol newAcc.name = context.unit.freshTermName(tree.symbol.name + "$") newAcc setFlag SYNTHETIC resetFlag (ACCESSOR | PARAMACCESSOR | PRIVATE | PROTECTED) newAcc.privateWithin = NoSymbol - newAcc = newAcc.owner.info.decls enter newAcc - val result = typer typed { DEF(newAcc) === rhs.duplicate } - log("new accessor method " + result) - result + newAcc.owner.info.decls enter newAcc + logResult("new accessor method")(newTypedMethod(newAcc)(rhs.duplicate)) } def needsReadResolve = ( - // only nested objects inside objects should get readResolve automatically - // otherwise after de-serialization we get null references for lazy accessors (nested object -> lazy val + class def) - // since the bitmap gets serialized but the moduleVar not + // Only nested objects inside objects should get readResolve automatically. + // Otherwise, after de-serialization we get null references for lazy accessors + // (nested object -> lazy val + class def) since the bitmap gets serialized but + // the moduleVar not. clazz.isSerializable && (clazz.owner.isPackageClass || clazz.owner.isModuleClass) ) @@ -320,13 +307,13 @@ trait SyntheticMethods extends ast.TreeDSL { * the readResolve() method (see http://www.javaworld.com/javaworld/ * jw-04-2003/jw-0425-designpatterns_p.html) */ - if (!hasReadResolve && needsReadResolve){ + if (!hasReadResolve && needsReadResolve) { // PP: To this day I really can't figure out what this next comment is getting at: // the !!! normally means there is something broken, but if so, what is it? // // !!! the synthetic method "readResolve" should be private, but then it is renamed !!! val method = newSyntheticMethod(nme.readResolve, PROTECTED, makeNoArgConstructor(ObjectClass.tpe)) - ts += typer typed (DEF(method) === REF(clazz.sourceModule)) + ts += newTypedMethod(method)(REF(clazz.sourceModule)) } } } catch { |