From 1536b1c67ecff52027a0c24d6791fb978fb88db4 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 21 Aug 2006 17:18:33 +0000 Subject: --- src/compiler/scala/tools/nsc/ast/TreeInfo.scala | 2 +- .../scala/tools/nsc/ast/TreePrinters.scala | 13 ++--- src/compiler/scala/tools/nsc/ast/Trees.scala | 6 ++ .../scala/tools/nsc/ast/parser/Parsers.scala | 24 +++++--- .../scala/tools/nsc/backend/jvm/GenJVM.scala | 2 +- src/compiler/scala/tools/nsc/symtab/Flags.scala | 20 ++++++- src/compiler/scala/tools/nsc/symtab/Symbols.scala | 22 ++++++-- src/compiler/scala/tools/nsc/symtab/Types.scala | 5 +- .../scala/tools/nsc/transform/Erasure.scala | 4 +- .../scala/tools/nsc/typechecker/Contexts.scala | 27 ++++----- .../scala/tools/nsc/typechecker/Infer.scala | 9 ++- .../scala/tools/nsc/typechecker/Namers.scala | 65 ++++++++++++++-------- .../scala/tools/nsc/typechecker/RefChecks.scala | 38 ++++++------- .../tools/nsc/typechecker/SyntheticMethods.scala | 2 +- .../scala/tools/nsc/typechecker/Typers.scala | 27 ++++++--- src/compiler/scala/tools/nsc/util/HashSet.scala | 11 ++-- 16 files changed, 179 insertions(+), 98 deletions(-) (limited to 'src/compiler') diff --git a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala index 0ba00d49b7..20c5b1ec56 100644 --- a/src/compiler/scala/tools/nsc/ast/TreeInfo.scala +++ b/src/compiler/scala/tools/nsc/ast/TreeInfo.scala @@ -191,7 +191,7 @@ abstract class TreeInfo { case Apply(fn, _) => fn.symbol != null && !fn.symbol.hasFlag(CASE) && - fn.symbol.isSubClass(definitions.SeqClass) + fn.symbol.isNonBottomSubClass(definitions.SeqClass) case Bind(name, body) => isSequencePattern(body) case Alternative(ts) => diff --git a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala index 5ed234ea19..64daebb8a7 100644 --- a/src/compiler/scala/tools/nsc/ast/TreePrinters.scala +++ b/src/compiler/scala/tools/nsc/ast/TreePrinters.scala @@ -56,7 +56,7 @@ abstract class TreePrinters { def printValueParams(ts: List[ValDef]): unit = { print("(") - if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, nme.EMPTY.toTypeName) + if (!ts.isEmpty) printFlags(ts.head.mods.flags & IMPLICIT, "") printSeq(ts){printParam}{print(", ")} print(")") } @@ -88,18 +88,17 @@ abstract class TreePrinters { def printModifiers(tree: Tree, mods: Modifiers): unit = { if (tree.symbol == NoSymbol) - printFlags(mods.flags, mods.privateWithin) + printFlags(mods.flags, mods.privateWithin.toString) else if (tree.symbol.privateWithin == NoSymbol || tree.symbol.privateWithin == tree.symbol.owner) - printFlags(tree.symbol.flags, nme.EMPTY.toTypeName) + printFlags(tree.symbol.flags, "") else - printFlags(tree.symbol.flags, tree.symbol.privateWithin.name) + printFlags(tree.symbol.flags, tree.symbol.privateWithin.name.toString) } - def printFlags(flags: long, privateWithin: Name): unit = { + def printFlags(flags: long, privateWithin: String): unit = { var mask = if (settings.debug.value) -1 else PrintableFlags - val s = flagsToString(flags & mask) - if (!privateWithin.isEmpty) print("private[" + privateWithin + "] ") + val s = flagsToString(flags & mask, privateWithin.toString) if (s.length() != 0) print(s + " ") } diff --git a/src/compiler/scala/tools/nsc/ast/Trees.scala b/src/compiler/scala/tools/nsc/ast/Trees.scala index 61ae3b6013..3c94b9334a 100644 --- a/src/compiler/scala/tools/nsc/ast/Trees.scala +++ b/src/compiler/scala/tools/nsc/ast/Trees.scala @@ -1269,6 +1269,12 @@ trait Trees requires Global { override def traverse(tree: Tree): unit = tree match { case EmptyTree | TypeTree() => ; + case Template(parents, body) => + tree.symbol = NoSymbol + tree.tpe = null + for (val stat <- body) + if (stat.isDef) erasedSyms.addEntry(stat.symbol) + super.traverse(tree) case _: DefTree => erasedSyms.addEntry(tree.symbol) tree.symbol = NoSymbol diff --git a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala index b942f73b22..282d2b5ce3 100644 --- a/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala +++ b/src/compiler/scala/tools/nsc/ast/parser/Parsers.scala @@ -1132,11 +1132,19 @@ trait Parsers requires SyntaxAnalyzer { /** Modifiers ::= {Modifier} * Modifier ::= LocalModifier - * | private [ "[" Id "]" ] - * | protected | override + * | override + * | (private | protected) [ "[" Id "]" ] */ def modifiers(): Modifiers = { var privateWithin: Name = nme.EMPTY.toTypeName; + def qualifierOpt: unit = + if (in.token == LBRACKET) { + in.nextToken() + if (privateWithin != nme.EMPTY.toTypeName) + syntaxError("duplicate private/protected qualifier", false) + privateWithin = ident().toTypeName + accept(RBRACKET) + } def loop(mods: int): int = in.token match { case ABSTRACT => loop(addMod(mods, Flags.ABSTRACT)) @@ -1146,15 +1154,13 @@ trait Parsers requires SyntaxAnalyzer { loop(addMod(mods, Flags.SEALED)) case PRIVATE => var mods1 = addMod(mods, Flags.PRIVATE) - if (in.token == LBRACKET) { - in.nextToken() - privateWithin = ident().toTypeName - accept(RBRACKET) - mods1 = mods - } + qualifierOpt + if (privateWithin != nme.EMPTY.toTypeName) mods1 = mods loop(mods1) case PROTECTED => - loop(addMod(mods, Flags.PROTECTED)) + val mods1 = addMod(mods, Flags.PROTECTED) + qualifierOpt + loop(mods1) case OVERRIDE => loop(addMod(mods, Flags.OVERRIDE)) case IMPLICIT => diff --git a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala index cff53734fe..12a56d5dc8 100644 --- a/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala +++ b/src/compiler/scala/tools/nsc/backend/jvm/GenJVM.scala @@ -703,7 +703,7 @@ abstract class GenJVM extends SubComponent { case Dynamic => if (method.owner.hasFlag(Flags.INTERFACE) || (method.owner.hasFlag(Flags.JAVA) && - method.owner.isSubClass(definitions.AttributeClass))) + method.owner.isNonBottomSubClass(definitions.AttributeClass))) jcode.emitINVOKEINTERFACE(owner, javaName(method), javaType(method).asInstanceOf[JMethodType]) diff --git a/src/compiler/scala/tools/nsc/symtab/Flags.scala b/src/compiler/scala/tools/nsc/symtab/Flags.scala index 12327875a0..eb245709df 100644 --- a/src/compiler/scala/tools/nsc/symtab/Flags.scala +++ b/src/compiler/scala/tools/nsc/symtab/Flags.scala @@ -117,9 +117,24 @@ object Flags { /** Module flags inherited by their module-class */ final val ModuleToClassFlags = AccessFlags | PACKAGE | CASE; + private def listToString(ss: List[String]): String = ss.filter("" !=).mkString("", " ", "") + def flagsToString(flags: long): String = - (for (val i <- List.range(0, 63)) yield flagToString(flags & (1L << i))) - .filter("" !=).mkString("", " ", ""); + listToString(for (val i <- List.range(0, 63)) yield flagToString(flags & (1L << i))) + + def flagsToString(flags: long, privateWithin: String): String = { + var f = flags; + val pw = + if (privateWithin == "") { + "" + } else if ((f & PROTECTED) != 0) { + f = f & ~PROTECTED + "protected["+privateWithin+"]" + } else { + "private["+privateWithin+"]" + } + listToString(List(flagsToString(f), pw)) + } private def flagToString(flag: long): String = { if (flag == IS_ERROR) "" @@ -172,6 +187,7 @@ object Flags { case _ => "" } } + class Flag(mods : int) { def isPrivate = ((mods & PRIVATE ) != 0); def isProtected = ((mods & PROTECTED) != 0); diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index cdde98a999..03e4549711 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -311,6 +311,16 @@ trait Symbols requires SymbolTable { final def hasFlag(mask: long): boolean = (flags & mask) != 0 final def resetFlags: unit = { rawflags = rawflags & TopLevelCreationFlags } + /** The class up to which this symbol is accessible, + * or NoSymbol if it is public or not a class member + */ + final def accessBoundary(base: Symbol): Symbol = { + if (hasFlag(PRIVATE)) owner + else if (privateWithin != NoSymbol && !phase.erasedTypes) privateWithin + else if (hasFlag(PROTECTED)) base + else NoSymbol + } + // Info and Type ------------------------------------------------------------------- private var infos: TypeHistory = null @@ -446,7 +456,7 @@ trait Symbols requires SymbolTable { } def getAttributes(clazz: Symbol): List[AttrInfo] = - attributes.filter(._1.symbol.isSubClass(clazz)) + attributes.filter(._1.symbol.isNonBottomSubClass(clazz)) /** Reset symbol to initial state */ @@ -484,14 +494,18 @@ trait Symbols requires SymbolTable { owner == that || owner != NoSymbol && (owner isNestedIn that) /** Is this class symbol a subclass of that symbol? */ - final def isSubClass(that: Symbol): boolean = ( + final def isNonBottomSubClass(that: Symbol): boolean = { this == that || this.isError || that.isError || - info.closurePos(that) >= 0 || + info.closurePos(that) >= 0 + } + + final def isSubClass(that: Symbol): boolean = { + isNonBottomSubClass(that) || this == AllClass || this == AllRefClass && (that == AnyClass || that != AllClass && (that isSubClass AnyRefClass)) - ) + } // Overloaded Alternatives --------------------------------------------------------- diff --git a/src/compiler/scala/tools/nsc/symtab/Types.scala b/src/compiler/scala/tools/nsc/symtab/Types.scala index 15006f7879..cfc4fd7c75 100644 --- a/src/compiler/scala/tools/nsc/symtab/Types.scala +++ b/src/compiler/scala/tools/nsc/symtab/Types.scala @@ -1326,7 +1326,8 @@ trait Types requires SymbolTable { case ThisType(sym) => def toPrefix(pre: Type, clazz: Symbol): Type = if ((pre eq NoType) || (pre eq NoPrefix) || !clazz.isClass) tp - else if ((sym isSubClass clazz) && (pre.widen.symbol isSubClass sym)) pre + else if ((sym isNonBottomSubClass clazz) && + (pre.widen.symbol isNonBottomSubClass sym)) pre else toPrefix(pre.baseType(clazz).prefix, clazz.owner); toPrefix(pre, clazz) case TypeRef(prefix, sym, args) if (sym.isTypeParameter) => @@ -1341,7 +1342,7 @@ trait Types requires SymbolTable { if (ps.isEmpty) throwError else if (sym eq ps.head) as.head else instParam(ps.tail, as.tail); - if (symclazz == clazz && (pre.widen.symbol isSubClass symclazz)) + if (symclazz == clazz && (pre.widen.symbol isNonBottomSubClass symclazz)) pre.baseType(symclazz) match { case TypeRef(_, basesym, baseargs) => // System.out.println("instantiating " + sym + " from " + basesym + " with " + basesym.typeParams + " and " + baseargs);//DEBUG diff --git a/src/compiler/scala/tools/nsc/transform/Erasure.scala b/src/compiler/scala/tools/nsc/transform/Erasure.scala index 98dfb5ef24..0cfb70dc44 100644 --- a/src/compiler/scala/tools/nsc/transform/Erasure.scala +++ b/src/compiler/scala/tools/nsc/transform/Erasure.scala @@ -243,7 +243,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { pt)) } } - else if (pt.symbol.isSubClass(BoxedArrayClass) && tree.tpe.symbol == ObjectClass) + else if (pt.symbol.isNonBottomSubClass(BoxedArrayClass) && tree.tpe.symbol == ObjectClass) typed { atPos(tree.pos) { evalOnce(tree, x => @@ -321,7 +321,7 @@ abstract class Erasure extends AddInterfaces with typechecker.Analyzer { // convert numeric type casts atPos(tree.pos)(Apply(Select(qual1, "to" + targClass.name), List())) else if (isValueClass(targClass) || - (targClass == ArrayClass && (qualClass isSubClass BoxedArrayClass))) + (targClass == ArrayClass && (qualClass isNonBottomSubClass BoxedArrayClass))) unbox(qual1, targ.tpe) else if (targClass == ArrayClass && qualClass == ObjectClass) cast(qual1, targ.tpe) diff --git a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala index b1a4b74133..27f3310c11 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Contexts.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Contexts.scala @@ -243,25 +243,22 @@ trait Contexts requires Analyzer { /** Is `clazz' a subclass of an enclosing class? */ def isSubClassOfEnclosing(clazz: Symbol): boolean = { var c = this.enclClass - while (c != NoContext && !clazz.isSubClass(c.owner)) c = c.outer.enclClass + while (c != NoContext && !clazz.isNonBottomSubClass(c.owner)) c = c.outer.enclClass c != NoContext } - ( pre == NoPrefix - || - (!sym.hasFlag(PRIVATE | PROTECTED)) - || - (accessWithin(sym.owner) || accessWithin(sym.owner.linkedClassOfClass)) && - (!sym.hasFlag(LOCAL) || pre =:= sym.owner.thisType) - || - (!sym.hasFlag(PRIVATE) && + (pre == NoPrefix) || { + val ab = sym.accessBoundary(sym.owner) + ((ab == NoSymbol) + || + (accessWithin(ab) || accessWithin(ab.linkedClassOfClass)) && + (!sym.hasFlag(LOCAL) || pre =:= sym.owner.thisType) + || + (sym hasFlag PROTECTED) && (superAccess || - (pre.widen.symbol.isSubClass(sym.owner) && isSubClassOfEnclosing(pre.widen.symbol)))) - ) && ( - sym.privateWithin == NoSymbol - || - phase.erasedTypes || accessWithin(sym.privateWithin) - ) + (pre.widen.symbol.isNonBottomSubClass(sym.owner) && + isSubClassOfEnclosing(pre.widen.symbol)))) + } } def pushTypeBounds(sym: Symbol): unit = { diff --git a/src/compiler/scala/tools/nsc/typechecker/Infer.scala b/src/compiler/scala/tools/nsc/typechecker/Infer.scala index b2cc60b3be..67a7c5e5ec 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Infer.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Infer.scala @@ -20,6 +20,10 @@ trait Infer requires Analyzer { /* -- Type parameter inference utility functions -------------------------------------- */ + def assertNonCyclic(tvar: TypeVar) = { + assert(tvar.constr.inst != tvar, tvar.origin) + } + /** The formal parameter types corresponding to `formals'. * If `formals' has a repeated last parameter, a list of * (nargs - params.length + 1) copies of its type is returned. */ @@ -58,7 +62,6 @@ trait Infer requires Analyzer { case WildcardType | NoType => throw new NoInstance("undetermined type"); case TypeVar(origin, constr) => - assert(constr.inst != null);//debug if (constr.inst != NoType) instantiate(constr.inst) else throw new DeferredNoInstance(() => "no unique instantiation of type variable " + origin + " could be found"); @@ -131,6 +134,7 @@ trait Infer requires Analyzer { //Console.println("solveOne2 "+tvar+" "+config+" "+tvar.constr.hibounds);//DEBUG tvar.constr.inst = NoType // necessary because hibounds/lobounds may contain tvar tvar.constr.inst = if (up) glb(tvar.constr.hibounds) else lub(tvar.constr.lobounds) + assertNonCyclic(tvar)//debug } } for (val Pair(tvar, Pair(tparam, variance)) <- config) solveOne(tvar, tparam, variance); @@ -306,13 +310,16 @@ trait Infer requires Analyzer { instantiate(tvar.constr.inst) } else if ((variance & COVARIANT) != 0 && !tvar.constr.hibounds.isEmpty) { tvar.constr.inst = glb(tvar.constr.hibounds); + assertNonCyclic(tvar)//debug instantiate(tvar.constr.inst) } else if ((variance & CONTRAVARIANT) != 0 && !tvar.constr.lobounds.isEmpty) { tvar.constr.inst = lub(tvar.constr.lobounds); + assertNonCyclic(tvar)//debug instantiate(tvar.constr.inst) } else if (!tvar.constr.hibounds.isEmpty && !tvar.constr.lobounds.isEmpty && glb(tvar.constr.hibounds) <:< lub(tvar.constr.lobounds)) { tvar.constr.inst = glb(tvar.constr.hibounds); + assertNonCyclic(tvar)//debug instantiate(tvar.constr.inst) } else { WildcardType diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index 8089e3079f..f0f19d839d 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -91,20 +91,10 @@ trait Namers requires Analyzer { (!prev.sym.isSourceMethod || nme.isSetterName(sym.name) || sym.owner.isPackageClass)) { -/* - if (sym.sourceFile == null && prev.sym.sourceFile == null) {} - - else if (sym.sourceFile != null && prev.sym.sourceFile != null && - sym.sourceFile.equals(prev.sym.sourceFile)) {} - else { - System.err.println("SYM: " + sym.sourceFile); - System.err.println("PRV: " + prev.sym.sourceFile); -*/ - doubleDefError(sym.pos, prev.sym); -// } - } - } - context.scope enter sym; + doubleDefError(sym.pos, prev.sym) + sym setInfo ErrorType + } else context.scope enter sym + } else context.scope enter sym sym } @@ -509,18 +499,41 @@ trait Namers requires Analyzer { new Namer(context.makeNewScope(tree, sym)).aliasTypeSig(sym, tparams, rhs) case AbsTypeDef(_, _, lo, hi) => - //System.out.println("bounds of " + sym + ":" + sym.tpe + " = " + typer.typedType(hi).tpe); - TypeBounds(typer.typedType(lo).tpe, typer.typedType(hi).tpe); + var lt = typer.typedType(lo).tpe + if (lt.isError) lt = AllClass.tpe + var ht = typer.typedType(hi).tpe + if (ht.isError) ht = AnyClass.tpe + TypeBounds(lt, ht) case Import(expr, selectors) => val expr1 = typer.typedQualifier(expr); val base = expr1.tpe; typer.checkStable(expr1); + def checkNotRedundant(pos: int, from: Name, to: Name): boolean = { + if (!base.symbol.isPackage && base.member(from) != NoSymbol) { + val e = context.scope.lookupEntry(to) + def warnRedundant(sym: Symbol) = + context.unit.warning(pos, "imported `"+to+ + "' is permanently hidden by definition of "+sym+ + sym.locationString) + if (e != null && e.owner == context.scope) { + warnRedundant(e.sym); return false + } else if (context eq context.enclClass) { + val defSym = context.prefix.member(to) filter ( + sym => sym.exists && context.isAccessible(sym, context.prefix, false)) + if (defSym != NoSymbol) { warnRedundant(defSym); return false } + } + } + true + } def checkSelectors(selectors: List[Pair[Name, Name]]): unit = selectors match { case Pair(from, to) :: rest => - if (from != nme.WILDCARD && base != ErrorType && - base.member(from) == NoSymbol && base.member(from.toTypeName) == NoSymbol) - context.error(tree.pos, from.decode + " is not a member of " + expr); + if (from != nme.WILDCARD && base != ErrorType) { + if (base.member(from) == NoSymbol && base.member(from.toTypeName) == NoSymbol) + context.error(tree.pos, from.decode + " is not a member of " + expr); + if (checkNotRedundant(tree.pos, from, to)) + checkNotRedundant(tree.pos, from.toTypeName, to.toTypeName) + } if (from != nme.WILDCARD && (rest.exists (sel => sel._1 == from))) context.error(tree.pos, from.decode + " is renamed twice"); if (to != null && to != nme.WILDCARD && (rest exists (sel => sel._2 == to))) @@ -597,18 +610,19 @@ trait Namers requires Analyzer { } /* Type `elemtp' is contained in type `tp' is one of the following holds: - * - elemtp is the same as some part of tp + * - elemtp is the same as some proper part of tp * - tp is a function type and elemtp is not * - tp and elemtp are function types, and arity of tp is greater than arity of elemtp * - tp and elemtp are both parameterized types with same type constructor and prefix, * and each type argument of elemtp is contained in the corresponding type argument of tp. */ private class ContainsTraverser(elemtp: Type) extends TypeTraverser { + var nested = false var result = false; def traverse(tp: Type): ContainsTraverser = { if (!result) { if (elemtp =:= tp) - result = true + result = nested else if (isFunctionType(tp) && (!isFunctionType(elemtp) || tp.typeArgs.length > elemtp.typeArgs.length)) result = true @@ -619,7 +633,14 @@ trait Namers requires Analyzer { case _ => } } - if (!result) mapOver(tp); + if (!result) { + tp match { + case SingleType(_, _) => nested = true + case TypeRef(_, _, _) => nested = true + case _ => + } + mapOver(tp) + } this } } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 5a2d7f8b7b..6a9d3b9ab4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -69,8 +69,6 @@ abstract class RefChecks extends InfoTransform { * 1.8.2 M is of type []S, O is of type ()T and S <: T, or * 1.8.3 M is of type ()S, O is of type []T and S <: T, or * 2. Check that only abstract classes have deferred members - * 3. Check that every member with an `override' modifier - * overrides some other member. */ private def checkAllOverrides(clazz: Symbol): unit = { @@ -113,6 +111,14 @@ abstract class RefChecks extends InfoTransform { } } + def overrideAccessError(): unit = { + val pwString = if (other.privateWithin == NoSymbol) "" + else other.privateWithin.name.toString + val otherAccess = flagsToString(other getFlag (PRIVATE | PROTECTED), pwString) + overrideError("has weaker access privileges; it should be "+ + (if (otherAccess == "") "public" else "at least "+otherAccess)) + } + //System.out.println(infoString(member) + " overrides " + infoString(other) + " in " + clazz);//DEBUG // return if we already checked this combination elsewhere @@ -136,13 +142,16 @@ abstract class RefChecks extends InfoTransform { } if (member hasFlag PRIVATE) { // (1.1) - overrideError("has weaker access privileges; it should not be private"); - } else if (member.privateWithin != NoSymbol && - !other.privateWithin.ownerChain.contains(member.privateWithin)) { - overrideError("has weaker access privileges; it should at least be private["+other.privateWithin.name+"]"); - } else if ((member hasFlag PROTECTED) && !(other hasFlag PROTECTED)) { // 1 - overrideError("has weaker access privileges; it should not be protected"); - } else if (other hasFlag FINAL) { // (1.2) + overrideError("has weaker access privileges; it should not be private") + } + val mb = member.accessBoundary(member.owner) + val ob = other.accessBoundary(member.owner) + if (mb != NoSymbol && + (ob == NoSymbol || + mb != ob && !(ob.ownerChain contains mb) || + (other hasFlag PROTECTED) && !(member hasFlag PROTECTED))) { + overrideAccessError() + } else if (other hasFlag FINAL) { // (1.2) overrideError("cannot override final member"); } else if (!(other hasFlag DEFERRED) && !(member hasFlag (OVERRIDE | ABSOVERRIDE))) { // (1.3) overrideError("needs `override' modifier"); @@ -230,17 +239,6 @@ abstract class RefChecks extends InfoTransform { else "")) } } - - // 3. Check that every defined member with an `override' modifier overrides some other member. - for (val member <- clazz.info.decls.toList) - if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && - (clazz.info.baseClasses.tail forall { - bc => member.matchingSymbol(bc, clazz.thisType) == NoSymbol - })) { - // for (val bc <- clazz.info.baseClasses.tail) System.out.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG - unit.error(member.pos, member.toString() + " overrides nothing"); - member resetFlag OVERRIDE - } } // Basetype Checking -------------------------------------------------------- diff --git a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala index 12a289d662..7c71ddbc84 100644 --- a/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala +++ b/src/compiler/scala/tools/nsc/typechecker/SyntheticMethods.scala @@ -30,7 +30,7 @@ trait SyntheticMethods requires Analyzer { val sym = clazz.info.nonPrivateMember(name) (sym.isTerm && (sym.owner == clazz || - !(ObjectClass isSubClass sym.owner) && !(sym hasFlag DEFERRED))) + !(ObjectClass isNonBottomSubClass sym.owner) && !(sym hasFlag DEFERRED))) } def syntheticMethod(name: Name, flags: Int, tpe: Type) = diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 7153fa49eb..c9b75eaf73 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -428,7 +428,7 @@ trait Typers requires Analyzer { throw t; } tree1 - } else if (clazz.isSubClass(SeqClass)) { // (5.2) + } else if (clazz.isNonBottomSubClass(SeqClass)) { // (5.2) val restpe = pt.baseType(clazz) restpe.baseType(SeqClass) match { case TypeRef(pre, seqClass, args) => @@ -947,8 +947,9 @@ trait Typers requires Analyzer { else Triple(FunctionClass(fun.vparams.length), fun.vparams map (x => NoType), WildcardType) - val Triple(clazz, argpts, respt) = - decompose(if (!forCLDC && (pt.symbol isSubClass CodeClass)) pt.typeArgs.head else pt) + val codeExpected = !forCLDC && (pt.symbol isNonBottomSubClass CodeClass) + + val Triple(clazz, argpts, respt) = decompose(if (codeExpected) pt.typeArgs.head else pt) if (fun.vparams.length != argpts.length) errorTree(fun, "wrong number of parameters; expected = "+argpts.length) @@ -974,7 +975,7 @@ trait Typers requires Analyzer { val funtpe = typeRef(clazz.tpe.prefix, clazz, formals ::: List(restpe)) val fun1 = copy.Function(fun, vparams, checkNoEscaping.locals(context.scope, restpe, body)) .setType(funtpe) - if (!forCLDC && (pt.symbol isSubClass CodeClass)) { + if (codeExpected) { val liftPoint = Apply(Select(Ident(CodeModule), nme.lift_), List(fun1)) typed(atPos(fun.pos)(liftPoint)) } else fun1 @@ -999,8 +1000,20 @@ trait Typers requires Analyzer { stat.symbol.initialize EmptyTree case _ => - (if (!inBlock && (!stat.isDef || stat.isInstanceOf[LabelDef])) - newTyper(context.make(stat, exprOwner)) else this).typed(stat) + val localTyper = if (inBlock || (stat.isDef && !stat.isInstanceOf[LabelDef])) this + else newTyper(context.make(stat, exprOwner)) + val stat1 = localTyper.typed(stat) + val member = stat1.symbol + // Check that every defined member with an `override' modifier + // overrides some other member + if (stat1.isDef && + (member hasFlag(OVERRIDE | ABSOVERRIDE)) && + (context.owner.info.baseClasses.tail forall + (bc => member.matchingSymbol(bc, context.owner.thisType) == NoSymbol))) { + error(member.pos, member.toString+" overrides nothing") + member resetFlag OVERRIDE + } + stat1 } } val scope = if (inBlock) context.scope else context.owner.info.decls; @@ -1097,7 +1110,7 @@ trait Typers requires Analyzer { val args1 = List.map2(args, formals)(typedArgToPoly) if (args1 exists (.tpe.isError)) setError(tree) else { - if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(.tpe)+", pt = "+pt+", lobounds = "+tparams.map(.tpe.bounds.lo));//debug + if (settings.debug.value) log("infer method inst "+fun+", tparams = "+tparams+", args = "+args1.map(.tpe)+", pt = "+pt+", lobounds = "+tparams.map(.tpe.bounds.lo)+", parambounds = "+tparams.map(.info));//debug val undetparams = inferMethodInstance(fun, tparams, args1, pt) val result = typedApply(tree, fun, args1, mode, pt) context.undetparams = undetparams diff --git a/src/compiler/scala/tools/nsc/util/HashSet.scala b/src/compiler/scala/tools/nsc/util/HashSet.scala index de84f9ca77..61ee86e180 100644 --- a/src/compiler/scala/tools/nsc/util/HashSet.scala +++ b/src/compiler/scala/tools/nsc/util/HashSet.scala @@ -24,13 +24,16 @@ class HashSet[T >: Null <: AnyRef](initialCapacity: int) extends Set[T] { } def addEntry(x: T): unit = { - if (used >= (capacity >> 2)) growTable; - used = used + 1; var h = x.hashCode() % capacity; - while (table(h) != null) { + var entry = table(h); + while (entry != null) { + if (entry == x) return h = (h + 1) % capacity + entry = table(h) } - table(h) = x + table(h) = x; + used = used + 1; + if (used >= (capacity >> 2)) growTable; } def elements = new Iterator[T] { -- cgit v1.2.3