diff options
author | Martin Odersky <odersky@gmail.com> | 2006-08-21 17:18:33 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2006-08-21 17:18:33 +0000 |
commit | 1536b1c67ecff52027a0c24d6791fb978fb88db4 (patch) | |
tree | ee544f3b5126e4393a2746d0b04281d413b1812e /src/compiler/scala/tools/nsc/typechecker | |
parent | 7f3d535727ff3fd8ba38e6fd55d474f76ed3ed90 (diff) | |
download | scala-1536b1c67ecff52027a0c24d6791fb978fb88db4.tar.gz scala-1536b1c67ecff52027a0c24d6791fb978fb88db4.tar.bz2 scala-1536b1c67ecff52027a0c24d6791fb978fb88db4.zip |
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
6 files changed, 102 insertions, 66 deletions
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 |