diff options
21 files changed, 415 insertions, 209 deletions
diff --git a/sources/scala/tools/nsc/Global.scala b/sources/scala/tools/nsc/Global.scala index a53da84903..30e05a306d 100755 --- a/sources/scala/tools/nsc/Global.scala +++ b/sources/scala/tools/nsc/Global.scala @@ -66,6 +66,10 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable val global: Global.this.type = Global.this } + object overridingPairs extends OverridingPairs { + val global: Global.this.type = Global.this + } + val copy = new LazyTreeCopier(); type AttrInfo = Pair[Type, List[Any]]; @@ -179,10 +183,11 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable val global: Global.this.type = Global.this } +/* object syntheticMethods extends SyntheticMethods { val global: Global.this.type = Global.this } - +*/ object refchecks extends RefChecks { val global: Global.this.type = Global.this; } @@ -240,10 +245,10 @@ class Global(val settings: Settings, val reporter: Reporter) extends SymbolTable } def phaseDescriptors: List[SubComponent] = List( - analyzer.namerFactory, // needs to be first - analyzer.typerFactory, // needs to be second + analyzer.namerFactory, + analyzer.typerFactory, pickler, - syntheticMethods, +// syntheticMethods, refchecks, uncurry, tailCalls, diff --git a/sources/scala/tools/nsc/ast/TreeGen.scala b/sources/scala/tools/nsc/ast/TreeGen.scala index a2541d8e74..d5f465dcf3 100755 --- a/sources/scala/tools/nsc/ast/TreeGen.scala +++ b/sources/scala/tools/nsc/ast/TreeGen.scala @@ -84,17 +84,22 @@ abstract class TreeGen { def This(sym: Symbol): Tree = global.This(sym.name) setSymbol sym setType sym.thisType; - def Ident(sym: Symbol) = { + def Ident(sym: Symbol): Tree = { assert(sym.isTerm); global.Ident(sym.name) setSymbol sym setType sym.tpe; } - def Select(qual: Tree, sym: Symbol) = { - assert(sym.isTerm); - val result = global.Select(qual, sym.name) setSymbol sym; - if (qual.tpe != null) result setType qual.tpe.memberType(sym); - result - } + def Select(qual: Tree, sym: Symbol): Tree = + if (qual.symbol != null && + (qual.symbol.name.toTermName == nme.ROOT || + qual.symbol.name.toTermName == nme.EMPTY_PACKAGE_NAME)) { + this.Ident(sym) + } else { + assert(sym.isTerm); + val result = global.Select(qual, sym.name) setSymbol sym; + if (qual.tpe != null) result setType qual.tpe.memberType(sym); + result + } /** Builds an instance test with given value and type. */ def mkIsInstanceOf(value: Tree, tpe: Type, erased: Boolean): Tree = { diff --git a/sources/scala/tools/nsc/ast/TreePrinters.scala b/sources/scala/tools/nsc/ast/TreePrinters.scala index 9678a70c9b..bda8158881 100644 --- a/sources/scala/tools/nsc/ast/TreePrinters.scala +++ b/sources/scala/tools/nsc/ast/TreePrinters.scala @@ -222,11 +222,7 @@ abstract class TreePrinters { print("this"); case Select(qualifier, name) => - if (global.settings.debug.value || qualifier.symbol == null || - (!qualifier.symbol.isRoot && !qualifier.symbol.isEmptyPackage)) { - print(qualifier); print("."); - } - print(symName(tree, name)) + print(qualifier); print("."); print(symName(tree, name)) case Ident(name) => print(symName(tree, name)) diff --git a/sources/scala/tools/nsc/symtab/InfoTransformers.scala b/sources/scala/tools/nsc/symtab/InfoTransformers.scala index d74a099537..bb03eaac8e 100644 --- a/sources/scala/tools/nsc/symtab/InfoTransformers.scala +++ b/sources/scala/tools/nsc/symtab/InfoTransformers.scala @@ -8,10 +8,11 @@ package scala.tools.nsc.symtab; abstract class InfoTransformers: SymbolTable { abstract class InfoTransformer { - private var prev: InfoTransformer = this; - private var next: InfoTransformer = this; + var prev: InfoTransformer = this; + var next: InfoTransformer = this; val phase: Phase; + val changesBaseClasses: boolean; def transform(sym: Symbol, tpe: Type): Type; def insert(that: InfoTransformer): unit = { diff --git a/sources/scala/tools/nsc/symtab/Scopes.scala b/sources/scala/tools/nsc/symtab/Scopes.scala index cc2da304c0..47c1bcb226 100755 --- a/sources/scala/tools/nsc/symtab/Scopes.scala +++ b/sources/scala/tools/nsc/symtab/Scopes.scala @@ -7,7 +7,7 @@ package scala.tools.nsc.symtab; abstract class Scopes: SymbolTable { - abstract class ScopeEntry(val sym: Symbol, val owner: Scope) { + class ScopeEntry(val sym: Symbol, val owner: Scope) { /** the next entry in the hash bucket */ @@ -21,9 +21,11 @@ abstract class Scopes: SymbolTable { override def toString(): String = sym.toString(); } - def newScopeEntry(sym: Symbol, owner: Scope) = new ScopeEntry(sym, owner) { - next = owner.elems; - owner.elems = this; + def newScopeEntry(sym: Symbol, owner: Scope): ScopeEntry = { + val e = new ScopeEntry(sym, owner); + e.next = owner.elems; + owner.elems = e; + e } object NoScopeEntry extends ScopeEntry(NoSymbol, null); @@ -98,7 +100,6 @@ abstract class Scopes: SymbolTable { /** enter a scope entry */ def enter(e: ScopeEntry): unit = { - elems = e; elemsCache = null; if (hashtable != null) { val i = e.sym.name.start & HASHMASK; diff --git a/sources/scala/tools/nsc/symtab/SymbolTable.scala b/sources/scala/tools/nsc/symtab/SymbolTable.scala index a7c0a61328..ba15a14b19 100755 --- a/sources/scala/tools/nsc/symtab/SymbolTable.scala +++ b/sources/scala/tools/nsc/symtab/SymbolTable.scala @@ -37,6 +37,7 @@ abstract class SymbolTable extends Names var infoTransformers = new InfoTransformer { val phase = NoPhase; + val changesBaseClasses = true; def transform(sym: Symbol, tpe: Type): Type = tpe; } } diff --git a/sources/scala/tools/nsc/symtab/Symbols.scala b/sources/scala/tools/nsc/symtab/Symbols.scala index 0a27a03948..abd68a107c 100755 --- a/sources/scala/tools/nsc/symtab/Symbols.scala +++ b/sources/scala/tools/nsc/symtab/Symbols.scala @@ -115,6 +115,7 @@ abstract class Symbols: SymbolTable { final def isMixinConstructor = isTerm && (name == nme.MIXIN_CONSTRUCTOR); final def isConstructor = isTerm && (name == nme.CONSTRUCTOR) || (name == nme.MIXIN_CONSTRUCTOR); final def isModule = isTerm && hasFlag(MODULE); + final def isStaticModule = isModule && isStatic && !isMethod; final def isPackage = isModule && hasFlag(PACKAGE); final def isThisSym = isTerm && name == nme.this_; final def isError = hasFlag(IS_ERROR); @@ -128,6 +129,7 @@ abstract class Symbols: SymbolTable { final def isModuleClass = isClass && hasFlag(MODULE); final def isPackageClass = isClass && hasFlag(PACKAGE); final def isRoot = isPackageClass && name == nme.ROOT.toTypeName; + final def isRootPackage = isPackage && name == nme.ROOT; final def isEmptyPackage = isPackage && name == nme.EMPTY_PACKAGE_NAME; final def isEmptyPackageClass = isPackageClass && name == nme.EMPTY_PACKAGE_NAME.toTypeName; @@ -483,7 +485,7 @@ abstract class Symbols: SymbolTable { */ final def linkedClass: Symbol = { if (owner.isPackageClass) - owner.info.decl(name.toTypeName).suchThat(sym => sym.rawInfo != NoType) + owner.info.decl(name.toTypeName).suchThat(sym => sym.rawInfo ne NoType) else NoSymbol; } @@ -493,7 +495,7 @@ abstract class Symbols: SymbolTable { final def linkedModule: Symbol = if (owner.isPackageClass) owner.info.decl(name.toTermName).suchThat( - sym => (sym hasFlag MODULE) && (sym.rawInfo != NoType)); + sym => (sym hasFlag MODULE) && (sym.rawInfo ne NoType)); else NoSymbol; /** The top-level class containing this symbol */ @@ -504,7 +506,7 @@ abstract class Symbols: SymbolTable { final def linkedSym: Symbol = if (isTerm) linkedClass else if (isClass && owner.isPackageClass) - owner.info.decl(name.toTermName).suchThat(sym => sym.rawInfo != NoType) + owner.info.decl(name.toTermName).suchThat(sym => sym.rawInfo ne NoType) else NoSymbol; final def toInterface: Symbol = @@ -723,6 +725,17 @@ abstract class Symbols: SymbolTable { private var referenced: Symbol = NoSymbol; + override def owner: Symbol = + if (phase.flatClasses && hasFlag(MODULE) && !hasFlag(METHOD) && + rawowner != NoSymbol && !rawowner.isPackageClass) rawowner.owner + else rawowner; + + override def name: Name = + if (phase.flatClasses && hasFlag(MODULE) && !hasFlag(METHOD) && + rawowner != NoSymbol && !rawowner.isPackageClass) + newTermName(rawowner.name.toString() + "$" + rawname); + else rawname; + def cloneSymbolImpl(owner: Symbol): Symbol = { val clone = new TermSymbol(owner, pos, name); clone.referenced = referenced; @@ -758,7 +771,7 @@ abstract class Symbols: SymbolTable { private var tpeCache: Type = _; private var tpePhase: Phase = null; override def tpe: Type = { - assert(tpeCache != NoType, this); + assert(tpeCache ne NoType, this); if (tpePhase != phase) { if (isValid(tpePhase)) { tpePhase = phase @@ -805,12 +818,12 @@ abstract class Symbols: SymbolTable { thissym = this; } + private var flatname = nme.EMPTY; + override def owner: Symbol = if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) rawowner.owner else rawowner; - private var flatname = nme.EMPTY; - override def name: Name = if (phase.flatClasses && rawowner != NoSymbol && !rawowner.isPackageClass) { if (flatname == nme.EMPTY) { @@ -875,7 +888,7 @@ abstract class Symbols: SymbolTable { /** An object repreesenting a missing symbol */ object NoSymbol extends Symbol(null, Position.NOPOS, nme.NOSYMBOL) { super.setInfo(NoType); - override def setInfo(info: Type): this.type = { assert(info == NoType); this } + override def setInfo(info: Type): this.type = { assert(info eq NoType); this } override def enclClass: Symbol = this; override def toplevelClass: Symbol = this; override def enclMethod: Symbol = this; diff --git a/sources/scala/tools/nsc/symtab/Types.scala b/sources/scala/tools/nsc/symtab/Types.scala index 366d9995b2..31126f8169 100755 --- a/sources/scala/tools/nsc/symtab/Types.scala +++ b/sources/scala/tools/nsc/symtab/Types.scala @@ -194,12 +194,12 @@ abstract class Types: SymbolTable { /** Is this type a subtype of that type? */ def <:<(that: Type): boolean = if (explainSwitch) explain("<", isSubType, this, that) - else this == that || isSubType(this, that); + else (this eq that) || isSubType(this, that); /** Is this type equivalent to that type? */ def =:=(that: Type): boolean = if (explainSwitch) explain("<", isSameType, this, that) - else this == that || isSameType(this, that); + else (this eq that) || isSameType(this, that); /** Does this type implement symbol `sym' with same or stronger type? */ def specializes(sym: Symbol): boolean = @@ -494,9 +494,6 @@ abstract class Types: SymbolTable { /** A common base class for intersection types and class types */ abstract class CompoundType extends Type { - override val parents: List[Type]; - override val decls: Scope; - assert(!parents.exists (.isInstanceOf[TypeBounds]), this);//debug private var closureCache: Array[Type] = _; @@ -519,7 +516,7 @@ abstract class Types: SymbolTable { val p = closurePhase; if (p != phase) { closurePhase = phase; - if (!isValid(p)) { + if (!isValidForBaseClasses(p)) { closureCache = null; closureCache = computeClosure } @@ -559,7 +556,7 @@ abstract class Types: SymbolTable { val p = baseClassesPhase; if (p != phase) { baseClassesPhase = phase; - if (!isValid(p)) { + if (!isValidForBaseClasses(p)) { baseClassesCache = null; baseClassesCache = computeBaseClasses; } @@ -639,7 +636,7 @@ abstract class Types: SymbolTable { val p = parentsPhase; if (p != phase) { parentsPhase = phase; - if (!isValid(p)) { + if (!isValidForBaseClasses(p)) { parentsCache = sym.info.parents map transform } } @@ -668,7 +665,7 @@ abstract class Types: SymbolTable { val p = closurePhase; if (p != phase) { closurePhase = phase; - if (!isValid(p)) { + if (!isValidForBaseClasses(p)) { typerefClosureCount = typerefClosureCount + 1; closureCache = if (sym.isAbstractType) addClosure(this, transform(bounds.hi).closure) @@ -770,7 +767,7 @@ abstract class Types: SymbolTable { case class TypeVar(origin: Type, constr: TypeConstraint) extends Type { override def symbol = origin.symbol; override def toString(): String = - if (constr.inst == NoType) "?" + origin else constr.inst.toString(); + if (constr.inst eq NoType) "?" + origin else constr.inst.toString(); } /** A class representing an as-yet unevaluated type. @@ -1114,17 +1111,17 @@ abstract class Types: SymbolTable { /** A map to compute the asSeenFrom method */ class AsSeenFromMap(pre: Type, clazz: Symbol) extends TypeMap { def apply(tp: Type): Type = - if (pre == NoType || pre == NoPrefix || !clazz.isClass) tp + if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else tp match { case ThisType(sym) => def toPrefix(pre: Type, clazz: Symbol): Type = - if (pre == NoType || pre == NoPrefix || !clazz.isClass) tp + if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else if ((sym isSubClass clazz) && (pre.widen.symbol isSubClass sym)) pre else toPrefix(pre.baseType(clazz).prefix, clazz.owner); toPrefix(pre, clazz) case TypeRef(prefix, sym, args) if (sym.isTypeParameter) => def toInstance(pre: Type, clazz: Symbol): Type = - if (pre == NoType || pre == NoPrefix || !clazz.isClass) tp + if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp else { val symclazz = sym.owner; def throwError = @@ -1256,10 +1253,20 @@ abstract class Types: SymbolTable { // Helper Methods ------------------------------------------------------------- final def isValid(p: Phase): boolean = - p != null && - (if (phase.id > p.id) infoTransformers.nextFrom(p).phase.id >= phase.id - else infoTransformers.nextFrom(phase).phase.id >= p.id); + p != null && { + if (phase.id > p.id) infoTransformers.nextFrom(p).phase.id >= phase.id + else infoTransformers.nextFrom(phase).phase.id >= p.id + } + final def isValidForBaseClasses(p: Phase): boolean = { + def noChangeInBaseClasses(it: InfoTransformer, limit: Phase): boolean = + it.phase.id >= limit.id || + !it.changesBaseClasses && noChangeInBaseClasses(it.next, limit); + p != null && { + if (phase.id > p.id) noChangeInBaseClasses(infoTransformers.nextFrom(p), phase) + else noChangeInBaseClasses(infoTransformers.nextFrom(phase), p) + } + } /** Do tp1 and tp2 denote equivalent types? */ def isSameType(tp1: Type, tp2: Type): boolean = (tp1 eq tp2) || { diff --git a/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala b/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala index a1da6db8fa..beb70991a5 100755 --- a/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala +++ b/sources/scala/tools/nsc/symtab/classfile/ClassfileParser.scala @@ -289,7 +289,7 @@ abstract class ClassfileParser { if (name == nme.CONSTRUCTOR) info match { case MethodType(formals, restpe) => - assert(restpe == definitions.UnitClass.tpe); + assert(restpe.symbol == definitions.UnitClass); info = MethodType(formals, clazz.tpe) } val sym = getOwner(jflags) diff --git a/sources/scala/tools/nsc/transform/Erasure.scala b/sources/scala/tools/nsc/transform/Erasure.scala index b50edd055b..f0a7e0d1f8 100755 --- a/sources/scala/tools/nsc/transform/Erasure.scala +++ b/sources/scala/tools/nsc/transform/Erasure.scala @@ -337,6 +337,24 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { e = e.next } + val opc = new overridingPairs.Cursor(root) { + override def exclude(sym: Symbol): boolean = + !sym.isTerm || (sym hasFlag (PRIVATE | BRIDGE)) || super.exclude(sym); + override def matches(sym1: Symbol, sym2: Symbol): boolean = + atPhase(phase.next)(sym1.tpe =:= sym2.tpe) + } + while (opc.hasNext) { + if (!atPhase(refchecksPhase.next)( + root.thisType.memberType(opc.overriding) matches + root.thisType.memberType(opc.overridden))) { + if (settings.debug.value) log("" + opc.overriding.locationString + " " + opc.overriding.infosString + opc.overridden.locationString + " " + opc.overridden.infosString); + doubleDefError(opc.overriding, opc.overridden) + } + opc.next + } + } + +/* for (val bc <- root.info.baseClasses.tail; val other <- bc.info.decls.toList) { if (other.isTerm && !other.isConstructor && !(other hasFlag (PRIVATE | BRIDGE))) { for (val member <- root.info.nonPrivateMember(other.name).alternatives) { @@ -351,7 +369,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { } } } - } +*/ /** Add bridge definitions to a template. This means: * If there is a concrete member `m' which overrides a member in a base class of the template, @@ -367,7 +385,19 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { val bridgesScope = new Scope(); val bridgeTarget = new HashMap[Symbol, Symbol]; var bridges: List[Tree] = List(); - for (val bc <- site.baseClasses.tail; val other <- bc.info.members) { + val opc = atPhase(phase.prev) { // to avoid DEFERRED flags for interfaces + new overridingPairs.Cursor(owner) { + override def parents: List[Type] = List(owner.info.parents.head); + override def exclude(sym: Symbol): boolean = + !sym.isMethod || (sym hasFlag (PRIVATE | BRIDGE)) || super.exclude(sym); + } + } + while (opc.hasNext) { + val member = opc.overriding; + val other = opc.overridden; + if (!(member hasFlag DEFERRED)) { +/* + for (val bc <- site.baseClasses.tail; val other <- bc.info.decls.toList) { if (other.isMethod && !other.isConstructor) { for (val member <- site.nonPrivateMember(other.name).alternatives) { if (member != other && @@ -375,6 +405,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { (site.memberType(member) matches site.memberType(other)) && !(site.parents exists (p => (p.symbol isSubClass member.owner) && (p.symbol isSubClass other.owner)))) { +*/ val otpe = erasure(other.tpe); if (!(otpe =:= erasure(member.tpe))) { var e = bridgesScope.lookupEntry(member.name); @@ -386,31 +417,43 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { setFlag (member.flags | BRIDGE) resetFlag ACCESSOR setInfo otpe; - if (settings.debug.value) - log("generating bridge from " + other + ":" + otpe + other.locationString + " to " + member + ":" + erasure(member.tpe) + "=" + bridge + ":" + bridge.tpe); bridgeTarget(bridge) = member; bridgesScope enter bridge; bridges = atPhase(phase.next) { atPos(bridge.pos) { - DefDef(bridge, vparamss => - member.tpe match { - case MethodType(List(), ConstantType(c)) => Literal(c) - case _ => - ((Select(This(owner), member): Tree) /: vparamss) - ((fun, vparams) => Apply(fun, vparams map Ident)) - }) + val bridgeDef = + DefDef(bridge, vparamss => + member.tpe match { + case MethodType(List(), ConstantType(c)) => Literal(c) + case _ => + ((Select(This(owner), member): Tree) /: vparamss) + ((fun, vparams) => Apply(fun, vparams map Ident)) + }); + if (settings.debug.value) + log("generating bridge from " + other + ":" + otpe + other.locationString + " to " + member + ":" + erasure(member.tpe) + member.locationString + " =\n " + bridgeDef); + bridgeDef } } :: bridges; } } - } +/* + } } +*/ } + opc.next } bridges } + def addBridges(stats: List[Tree], base: Symbol): List[Tree] = + if (base.isTrait) stats + else { + val bridges = bridgeDefs(base); + if (bridges.isEmpty) stats else stats ::: bridges + } + /** Transform tree at phase `erasure' before retyping it. This entails the following: * - Remove all type parameters in class and method definitions. * - Remove all abstract and alias type definitions. @@ -438,9 +481,10 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { // leave type tests/type casts, remove all other type applications fun case Template(parents, body) => + assert(!currentOwner.isImplClass); //System.out.println("checking no dble defs " + tree);//DEBUG checkNoDoubleDefs(tree.symbol.owner); - copy.Template(tree, parents, body ::: bridgeDefs(currentOwner)); + copy.Template(tree, parents, addBridges(body, currentOwner)); case _ => tree } diff --git a/sources/scala/tools/nsc/transform/ExplicitOuter.scala b/sources/scala/tools/nsc/transform/ExplicitOuter.scala index 469cabdcb7..5796f1c6f6 100755 --- a/sources/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/sources/scala/tools/nsc/transform/ExplicitOuter.scala @@ -19,6 +19,7 @@ abstract class ExplicitOuter extends InfoTransform { /** the following two members override abstract members in Transform */ val phaseName: String = "explicitouter"; + override def changesBaseClasses = false; final val needSuperAccessors = false; diff --git a/sources/scala/tools/nsc/transform/Flatten.scala b/sources/scala/tools/nsc/transform/Flatten.scala index 6a66c86c41..0af811cf3f 100755 --- a/sources/scala/tools/nsc/transform/Flatten.scala +++ b/sources/scala/tools/nsc/transform/Flatten.scala @@ -13,6 +13,7 @@ import collection.mutable.HashMap; abstract class Flatten extends InfoTransform { import global._; import definitions._; + import posAssigner.atPos; /** the following two members override abstract members in Transform */ val phaseName: String = "flatten"; @@ -45,8 +46,9 @@ abstract class Flatten extends InfoTransform { atPhase(phase.next)(oldowner.info); parents1 = List.mapConserve(parents)(this); for (val sym <- decls.toList) { - if (sym.isTerm) decls1 enter sym - else if (sym.isClass) { + if (sym.isTerm && !sym.isStaticModule) { + decls1 enter sym + } else if (sym.isClass) { liftClass(sym); if (sym.needsImplClass) liftClass(erasure.implClass(sym)) } @@ -91,14 +93,22 @@ abstract class Flatten extends InfoTransform { val mix1 = if (ps.head.symbol.isNestedClass) atPhase(phase.next)(ps.head.symbol.name) else mix; copy.Super(tree, qual, mix1) + case Select(qual, name) if (sym.isStaticModule && !sym.owner.isPackageClass) => + atPhase(phase.next) { + atPos(tree.pos) { + gen.mkRef(sym) + } + } case _ => tree } tree1 setType flattened(tree1.tpe); +/* if (sym != null && sym.isNestedClass && !(sym hasFlag LIFTED)) { liftClass(sym);//todo: remove if (sym.implClass != NoSymbol) liftClass(sym.implClass); } +*/ tree1 } diff --git a/sources/scala/tools/nsc/transform/InfoTransform.scala b/sources/scala/tools/nsc/transform/InfoTransform.scala index c6d2997c65..5710dc7483 100755 --- a/sources/scala/tools/nsc/transform/InfoTransform.scala +++ b/sources/scala/tools/nsc/transform/InfoTransform.scala @@ -15,9 +15,12 @@ abstract class InfoTransform extends Transform { override def newPhase(prev: scala.tools.nsc.Phase): StdPhase = new Phase(prev); + protected def changesBaseClasses = true; + class Phase(prev: scala.tools.nsc.Phase) extends super.Phase(prev) { val infoTransformer = new InfoTransformer { val phase = Phase.this; + val changesBaseClasses = InfoTransform.this.changesBaseClasses; def transform(sym: Symbol, tpe: Type): Type = transformInfo(sym, tpe); } infoTransformers.insert(infoTransformer) diff --git a/sources/scala/tools/nsc/transform/Mixin.scala b/sources/scala/tools/nsc/transform/Mixin.scala index 5c627fa2d0..ff56fcfd2b 100755 --- a/sources/scala/tools/nsc/transform/Mixin.scala +++ b/sources/scala/tools/nsc/transform/Mixin.scala @@ -52,16 +52,6 @@ abstract class Mixin extends InfoTransform { decls1 enter member; member } - def addPackageClassMembers = { - for (val sym <- decls.toList) { - if (sym.isImplClass) { - sym setFlag lateMODULE | notABSTRACT; - addMember( - clazz.newModule(sym.pos, sym.name.toTermName, sym.asInstanceOf[ClassSymbol]) - setInfo sym.tpe) - } - } - } def addLateInterfaceMembers = { def newGetter(field: Symbol): Symbol = clazz.newMethod(field.pos, nme.getterName(field.name)) @@ -85,7 +75,7 @@ abstract class Mixin extends InfoTransform { var setter = member.setter(clazz); if (setter == NoSymbol) setter = addMember(newSetter(member)); } - } else if ((member hasFlag LIFTED) && !(member hasFlag PRIVATE)) { + } else if ((member hasFlag (LIFTED | BRIDGE)) && !(member hasFlag PRIVATE)) { member.expandName(clazz); addMember(member.cloneSymbol(clazz)); } @@ -120,7 +110,7 @@ abstract class Mixin extends InfoTransform { val member1 = addMember(member.cloneSymbol(clazz)) setFlag MIXEDIN; assert(member1.alias != NoSymbol, member1); member1.asInstanceOf[TermSymbol] setAlias rebindSuper(clazz, member.alias, bc); - } else if (member.isMethod && member.isModule && !(member hasFlag LIFTED)) { + } else if (member.isMethod && member.isModule && !(member hasFlag (LIFTED | BRIDGE))) { addMember(member.cloneSymbol(clazz) setFlag MIXEDIN) } } @@ -128,11 +118,14 @@ abstract class Mixin extends InfoTransform { } } - if (clazz.isPackageClass) { - addPackageClassMembers - } else { + if (!clazz.isPackageClass) { atPhase(phase.next)(clazz.owner.info); if (clazz.isImplClass) { + clazz setFlag lateMODULE; + clazz.owner.info.decls.enter( + clazz.owner.newModule(sym.pos, sym.name.toTermName, sym.asInstanceOf[ClassSymbol]) + setInfo sym.tpe); + assert(clazz.sourceModule != NoSymbol);//debug parents1 = List(); decls1 = new Scope(decls.toList filter isForwarded) } else if (!parents.isEmpty) { @@ -140,15 +133,16 @@ abstract class Mixin extends InfoTransform { if (!(clazz hasFlag INTERFACE)) addMixedinMembers else if (clazz hasFlag lateINTERFACE) addLateInterfaceMembers } + if (settings.debug.value) log("new defs of " + clazz + " = " + decls1); } - if (settings.debug.value && !clazz.isPackageClass) log("new defs of " + clazz + " = " + decls1); - decls1 = atPhase(phase.next)(new Scope(decls1.toList));//debug + //decls1 = atPhase(phase.next)(new Scope(decls1.toList));//debug if ((parents1 eq parents) && (decls1 eq decls)) tp else ClassInfoType(parents1, decls1, clazz); case MethodType(formals, restp) => if (isForwarded(sym)) MethodType(toInterface(sym.owner.typeOfThis) :: formals, restp) else tp + case _ => tp } @@ -189,8 +183,10 @@ abstract class Mixin extends InfoTransform { private def staticRef(sym: Symbol) = { sym.owner.info; - if (sym.owner.sourceModule == NoSymbol) + sym.owner.owner.info; + if (sym.owner.sourceModule == NoSymbol) { assert(false, "" + sym + " in " + sym.owner + " in " + sym.owner.owner + " " + sym.owner.owner.info.decls.toList);//debug + } Select(gen.mkRef(sym.owner.sourceModule), sym); } @@ -298,7 +294,7 @@ abstract class Mixin extends InfoTransform { } case Select(qual, name) if sym.owner.isImplClass && !isStatic(sym) => if (sym.isMethod) { - assert(sym hasFlag LIFTED, sym); + assert(sym hasFlag (LIFTED | BRIDGE), sym); val sym1 = enclInterface.info.decl(sym.name); assert(sym1 != NoSymbol && !(sym1 hasFlag OVERLOADED), sym);//debug tree setSymbol sym1 diff --git a/sources/scala/tools/nsc/transform/OverridingPairs.scala b/sources/scala/tools/nsc/transform/OverridingPairs.scala new file mode 100755 index 0000000000..2830fed9f5 --- /dev/null +++ b/sources/scala/tools/nsc/transform/OverridingPairs.scala @@ -0,0 +1,126 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author + */ +// $Id$ +package scala.tools.nsc.transform; + +import util.HashSet; +import collection.mutable.HashMap; +import symtab.Flags._; + +abstract class OverridingPairs { + + val global: Global; + import global._; + + class Cursor(base: Symbol) { + + private val self = base.thisType; + + protected def exclude(sym: Symbol): boolean = sym.isConstructor || (sym hasFlag LOCAL); + + protected def parents: List[Type] = base.info.parents; + + protected def matches(sym1: Symbol, sym2: Symbol): boolean = + sym1.isType || (self.memberType(sym1) matches self.memberType(sym2)); + + private type BitSet = Array[int]; + + private def newBitSet(size: int): BitSet = new Array((size + 31) >> 5); + + private def include(bs: BitSet, n: int): unit = { + val nshifted = n >> 5; + val nmask = 1 << (n & 31); + bs(nshifted) = bs(nshifted) | nmask + } + + private def intersectionContainsElementLeq(bs1: BitSet, bs2: BitSet, n: int): boolean = { + val nshifted = n >> 5; + val nmask = 1 << (n & 31); + (List.range(0, nshifted) exists (i => (bs1(i) & bs2(i)) != 0)) || + ((bs1(nshifted) & bs2(nshifted) & (nmask | nmask - 1)) != 0) + } + + private val decls = new Scope; + { def fillDecls(bcs: List[Symbol], deferredflag: int): unit = + if (!bcs.isEmpty) { + fillDecls(bcs.tail, deferredflag); + var e = bcs.head.info.decls.elems; + while (e != null) { + if (e.sym.getFlag(DEFERRED) == deferredflag && !exclude(e.sym)) decls enter e.sym; + e = e.next + } + } + fillDecls(base.info.baseClasses, DEFERRED); + fillDecls(base.info.baseClasses, 0); + } + + private val size = base.info.baseClasses.length; + + private val index = new HashMap[Symbol, int]; + { var i = 0; + for (val bc <- base.info.baseClasses) { + index(bc) = i; + i = i + 1 + } + } + + private val subParents = new Array[BitSet](size); + { for (val i <- List.range(0, size)) + subParents(i) = new BitSet(size); + for (val p <- parents) { + val pIndex = index(p.symbol); + for (val bc <- p.baseClasses) include(subParents(index(bc)), pIndex); + } + } + + + private def hasCommonParent(sym1: Symbol, sym2: Symbol) = { + //assert(index.get(sym1.owner) != None, "" + base + " " + sym1 + " " + sym1.owner);//DEBUG + //assert(index.get(sym2.owner) != None, "" + base + " " + sym2 + " " + sym2.owner);//DEBUG + val index1 = index(sym1.owner); + val index2 = index(sym2.owner); + val minindex = if (index1 < index2) index1 else index2; + intersectionContainsElementLeq(subParents(index1), subParents(index2), minindex) + } + + private val visited = new HashSet[ScopeEntry](256); + private var curEntry = decls.elems; + private var nextEntry = curEntry; + + var overriding: Symbol = _; + var overridden: Symbol = _; + + def hasNext: boolean = curEntry != null; + + def next: unit = + if (curEntry != null) { + overriding = curEntry.sym; + if (nextEntry != null) { + do { + nextEntry = decls.lookupNextEntry(nextEntry); + } while (nextEntry != null && + ((nextEntry.sym hasFlag PRIVATE) || + (overriding.owner == nextEntry.sym.owner) || + (hasCommonParent(overriding, nextEntry.sym)) || + (!matches(overriding, nextEntry.sym)) || + (overriding hasFlag LOCAL))) + } + if (nextEntry != null) { + overridden = nextEntry.sym; + //System.out.println("yield: " + overriding + overriding.locationString + " / " + overridden + overridden.locationString);//DEBUG + visited addEntry nextEntry + } else { + do { + curEntry = curEntry.next + } while (curEntry != null && (visited contains curEntry)); + nextEntry = curEntry; + next + } + } + + next + } +} + diff --git a/sources/scala/tools/nsc/transform/SyntheticMethods.scala b/sources/scala/tools/nsc/transform/SyntheticMethods.scala deleted file mode 100644 index 5f84f49206..0000000000 --- a/sources/scala/tools/nsc/transform/SyntheticMethods.scala +++ /dev/null @@ -1,124 +0,0 @@ -/* NSC -- new scala compiler - * Copyright 2005 LAMP/EPFL - * @author - */ -// $Id$ -package scala.tools.nsc.transform; - -import symtab.Flags._; -import util.ListBuffer; - -abstract class SyntheticMethods extends Transform { - import global._; // the global environment - import definitions._; // standard classes and methods - import typer.{typed}; // methods to type trees - - val phaseName: String = "syntheticMethods"; - def newTransformer(unit: CompilationUnit): Transformer = new SyntheticMethodTransformer; - - class SyntheticMethodTransformer extends Transformer { - - private def addSyntheticMethods(templ: Template, clazz: Symbol): Template = { - - def hasImplementation(name: Name): boolean = { - val sym = clazz.info.nonPrivateMember(name); - sym.isTerm && - (sym.owner == clazz || - !(ObjectClass isSubClass sym.owner) && !(sym hasFlag DEFERRED)); - } - - def syntheticMethod(name: Name, flags: int, tpe: Type) = { - val method = clazz.newMethod(clazz.pos, name) setFlag (flags | OVERRIDE) setInfo tpe; - clazz.info.decls.enter(method); - method - } - - def caseElementMethod: Tree = { - val method = syntheticMethod( - nme.caseElement, FINAL, MethodType(List(IntClass.tpe), AnyClass.tpe)); - val caseFields = clazz.caseFieldAccessors map gen.mkRef; - typed( - DefDef(method, vparamss => - if (caseFields.isEmpty) Literal(Constant(null)) - else { - var i = caseFields.length; - var cases = List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(null)))); - for (val field <- caseFields.reverse) { - i = i - 1; cases = CaseDef(Literal(Constant(i)), EmptyTree, field) :: cases - } - Match(Ident(vparamss.head.head), cases) - })) - } - - def caseArityMethod: Tree = { - val method = syntheticMethod(nme.caseArity, FINAL, PolyType(List(), IntClass.tpe)); - typed(DefDef(method, vparamss => Literal(Constant(clazz.caseFieldAccessors.length)))) - } - - def caseNameMethod: Tree = { - val method = syntheticMethod(nme.caseName, FINAL, PolyType(List(), StringClass.tpe)); - typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) - } - - def moduleToStringMethod: Tree = { - val method = syntheticMethod(nme.toString_, FINAL, MethodType(List(), StringClass.tpe)); - typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) - } - - def tagMethod: Tree = { - val method = syntheticMethod(nme.tag, FINAL, MethodType(List(), IntClass.tpe)); - typed(DefDef(method, vparamss => Literal(Constant(clazz.tag)))) - } - - def forwardingMethod(name: Name): Tree = { - val target = getMember(ScalaRunTimeModule, "_" + name); - val method = syntheticMethod( - name, 0, MethodType(target.tpe.paramTypes.tail, target.tpe.resultType)); - typed(DefDef(method, vparamss => - Apply(gen.mkRef(target), This(clazz) :: (vparamss.head map Ident)))); - } - - def readResolveMethod: Tree = { - // !!! the synthetic method "readResolve" should be private, - // but then it is renamed !!! - val method = syntheticMethod(nme.readResolve, PROTECTED, MethodType(List(), ObjectClass.tpe)); - typed(DefDef(method, vparamss => gen.mkRef(clazz.sourceModule))) - } - - val ts = new ListBuffer[Tree]; - if (clazz hasFlag CASE) { - ts += tagMethod; - if (clazz.isModuleClass) { - if (!hasImplementation(nme.toString_)) ts += moduleToStringMethod; - if (clazz.isSubClass(SerializableClass)) { - // If you serialize a singleton and then deserialize it twice, - // you will have two instances of your singleton, unless you implement - // the readResolve() method (see http://www.javaworld.com/javaworld/ - // jw-04-2003/jw-0425-designpatterns_p.html) - if (!hasImplementation(nme.readResolve)) ts += readResolveMethod; - } - } else { - ts += caseElementMethod; - ts += caseArityMethod; - ts += caseNameMethod; - if (!hasImplementation(nme.equals_)) ts += forwardingMethod(nme.equals_); - if (!hasImplementation(nme.hashCode_)) ts += forwardingMethod(nme.hashCode_); - if (!hasImplementation(nme.toString_)) ts += forwardingMethod(nme.toString_); - } - } - val synthetics = ts.toList; - copy.Template( - templ, templ.parents, if (synthetics.isEmpty) templ.body else templ.body ::: synthetics) - } - - override def transform(tree: Tree): Tree = - super.transform { - tree match { - case ClassDef(mods, name, tparams, tpe, impl) => - copy.ClassDef(tree, mods, name, tparams, tpe, addSyntheticMethods(impl, tree.symbol)) - case _ => - tree - } - } - } -} diff --git a/sources/scala/tools/nsc/transform/UnCurry.scala b/sources/scala/tools/nsc/transform/UnCurry.scala index a252c47d32..05c9be4f54 100755 --- a/sources/scala/tools/nsc/transform/UnCurry.scala +++ b/sources/scala/tools/nsc/transform/UnCurry.scala @@ -33,6 +33,7 @@ abstract class UnCurry extends InfoTransform { val phaseName: String = "uncurry"; def newTransformer(unit: CompilationUnit): Transformer = new UnCurryTransformer(unit); + override def changesBaseClasses = false; private val uncurry = new TypeMap { def apply(tp: Type): Type = tp match { diff --git a/sources/scala/tools/nsc/typechecker/Analyzer.scala b/sources/scala/tools/nsc/typechecker/Analyzer.scala index a0f3f19a8f..267f5ba39c 100644 --- a/sources/scala/tools/nsc/typechecker/Analyzer.scala +++ b/sources/scala/tools/nsc/typechecker/Analyzer.scala @@ -14,7 +14,8 @@ abstract class Analyzer with Typers with Infer with Variances - with EtaExpansion { + with EtaExpansion + with SyntheticMethods { val global: Global; import global._; diff --git a/sources/scala/tools/nsc/typechecker/RefChecks.scala b/sources/scala/tools/nsc/typechecker/RefChecks.scala index f78c74c821..a32c7bf0e5 100755 --- a/sources/scala/tools/nsc/typechecker/RefChecks.scala +++ b/sources/scala/tools/nsc/typechecker/RefChecks.scala @@ -43,6 +43,7 @@ abstract class RefChecks extends InfoTransform { /** the following two members override abstract members in Transform */ val phaseName: String = "refchecks"; def newTransformer(unit: CompilationUnit): Transformer = new RefCheckTransformer(unit); + override def changesBaseClasses = false; def transformInfo(sym: Symbol, tp: Type): Type = { if (sym.isModule && !sym.isStatic) { @@ -178,6 +179,14 @@ abstract class RefChecks extends InfoTransform { } } + val opc = new overridingPairs.Cursor(clazz); + while (opc.hasNext) { + //System.out.println("overrides " + opc.overriding/* + ":" + opc.overriding.tpe*/ + opc.overriding.locationString + " " + opc.overridden/* + ":" + opc.overridden.tpe*/ + opc.overridden.locationString + opc.overridden.hasFlag(DEFERRED));//DEBUG + if (!opc.overridden.isClass) checkOverride(clazz, opc.overriding, opc.overridden); + + opc.next + } +/* // 1. Check all members for overriding conditions. for (val bc <- clazz.info.baseClasses.tail; val other <- bc.info.decls.toList) if (!other.isClass && !(other hasFlag PRIVATE) && !other.isConstructor) { @@ -195,10 +204,11 @@ abstract class RefChecks extends InfoTransform { "\n and " + infoString(alt2) + "\n override " + infoString(other)); } else if (member != NoSymbol && !(member hasFlag LOCAL)) { + System.out.println("OVERRIDES " + member + member.locationString + " " + other + other.locationString);//debug checkOverride(clazz, member, other); } } - +*/ // 2. Check that only abstract classes have deferred members if (clazz.isClass && !(clazz hasFlag ABSTRACT)) { def abstractClassError(msg: String): unit = { diff --git a/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala b/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala new file mode 100755 index 0000000000..dafad66d54 --- /dev/null +++ b/sources/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -0,0 +1,108 @@ +/* NSC -- new scala compiler + * Copyright 2005 LAMP/EPFL + * @author + */ +// $Id$ +package scala.tools.nsc.typechecker; + +import symtab.Flags._; +import util.ListBuffer; + +abstract class SyntheticMethods: Analyzer { + import global._; // the global environment + import definitions._; // standard classes and methods + import typer.{typed}; // methods to type trees + + def addSyntheticMethods(templ: Template, clazz: Symbol): Template = { + + def hasImplementation(name: Name): boolean = { + val sym = clazz.info.nonPrivateMember(name); + sym.isTerm && + (sym.owner == clazz || + !(ObjectClass isSubClass sym.owner) && !(sym hasFlag DEFERRED)); + } + + def syntheticMethod(name: Name, flags: int, tpe: Type) = { + val method = clazz.newMethod(clazz.pos, name) setFlag (flags | OVERRIDE) setInfo tpe; + clazz.info.decls.enter(method); + method + } + + def caseElementMethod: Tree = { + val method = syntheticMethod( + nme.caseElement, FINAL, MethodType(List(IntClass.tpe), AnyClass.tpe)); + val caseFields = clazz.caseFieldAccessors map gen.mkRef; + typed( + DefDef(method, vparamss => + if (caseFields.isEmpty) Literal(Constant(null)) + else { + var i = caseFields.length; + var cases = List(CaseDef(Ident(nme.WILDCARD), EmptyTree, Literal(Constant(null)))); + for (val field <- caseFields.reverse) { + i = i - 1; cases = CaseDef(Literal(Constant(i)), EmptyTree, field) :: cases + } + Match(Ident(vparamss.head.head), cases) + })) + } + + def caseArityMethod: Tree = { + val method = syntheticMethod(nme.caseArity, FINAL, PolyType(List(), IntClass.tpe)); + typed(DefDef(method, vparamss => Literal(Constant(clazz.caseFieldAccessors.length)))) + } + + def caseNameMethod: Tree = { + val method = syntheticMethod(nme.caseName, FINAL, PolyType(List(), StringClass.tpe)); + typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + } + + def moduleToStringMethod: Tree = { + val method = syntheticMethod(nme.toString_, FINAL, MethodType(List(), StringClass.tpe)); + typed(DefDef(method, vparamss => Literal(Constant(clazz.name.decode)))) + } + + def tagMethod: Tree = { + val method = syntheticMethod(nme.tag, FINAL, MethodType(List(), IntClass.tpe)); + typed(DefDef(method, vparamss => Literal(Constant(clazz.tag)))) + } + + def forwardingMethod(name: Name): Tree = { + val target = getMember(ScalaRunTimeModule, "_" + name); + val method = syntheticMethod( + name, 0, MethodType(target.tpe.paramTypes.tail, target.tpe.resultType)); + typed(DefDef(method, vparamss => + Apply(gen.mkRef(target), This(clazz) :: (vparamss.head map Ident)))); + } + + def readResolveMethod: Tree = { + // !!! the synthetic method "readResolve" should be private, + // but then it is renamed !!! + val method = syntheticMethod(nme.readResolve, PROTECTED, MethodType(List(), ObjectClass.tpe)); + typed(DefDef(method, vparamss => gen.mkRef(clazz.sourceModule))) + } + + val ts = new ListBuffer[Tree]; + if (clazz hasFlag CASE) { + if (!hasImplementation(nme.tag)) ts += tagMethod; + if (clazz.isModuleClass) { + if (!hasImplementation(nme.toString_)) ts += moduleToStringMethod; + if (clazz.isSubClass(SerializableClass)) { + // If you serialize a singleton and then deserialize it twice, + // you will have two instances of your singleton, unless you implement + // the readResolve() method (see http://www.javaworld.com/javaworld/ + // jw-04-2003/jw-0425-designpatterns_p.html) + if (!hasImplementation(nme.readResolve)) ts += readResolveMethod; + } + } else { + if (!hasImplementation(nme.caseElement)) ts += caseElementMethod; + if (!hasImplementation(nme.caseArity)) ts += caseArityMethod; + if (!hasImplementation(nme.caseName)) ts += caseNameMethod; + if (!hasImplementation(nme.equals_)) ts += forwardingMethod(nme.equals_); + if (!hasImplementation(nme.hashCode_)) ts += forwardingMethod(nme.hashCode_); + if (!hasImplementation(nme.toString_)) ts += forwardingMethod(nme.toString_); + } + } + val synthetics = ts.toList; + copy.Template( + templ, templ.parents, if (synthetics.isEmpty) templ.body else templ.body ::: synthetics) + } +} diff --git a/sources/scala/tools/nsc/typechecker/Typers.scala b/sources/scala/tools/nsc/typechecker/Typers.scala index ffef937b0a..5c2ff01376 100755 --- a/sources/scala/tools/nsc/typechecker/Typers.scala +++ b/sources/scala/tools/nsc/typechecker/Typers.scala @@ -474,7 +474,8 @@ abstract class Typers: Analyzer { val tpt1 = checkNoEscaping.privates(clazz.thisSym, typedType(cdef.tpt)); val impl1 = newTyper(context.make(cdef.impl, clazz, new Scope())) .typedTemplate(cdef.impl); - copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, impl1) setType NoType + copy.ClassDef(cdef, cdef.mods, cdef.name, tparams1, tpt1, addSyntheticMethods(impl1, clazz)) + setType NoType } def typedModuleDef(mdef: ModuleDef): Tree = { @@ -907,7 +908,7 @@ abstract class Typers: Analyzer { val sym = if (tree.symbol != NoSymbol) { if (phase.erasedTypes && qual.isInstanceOf[Super]) qual.tpe = tree.symbol.owner.tpe; - if (settings.debug.value) { // todo: replace by settings.check.value? + if (false && settings.debug.value) { // todo: replace by settings.check.value? val alts = qual.tpe.member(tree.symbol.name).alternatives; if (!(alts exists (alt => alt == tree.symbol || alt.isTerm && (alt.tpe matches tree.symbol.tpe)))) |