diff options
author | Martin Odersky <odersky@gmail.com> | 2006-09-19 10:48:26 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2006-09-19 10:48:26 +0000 |
commit | f72b4dfe467a967f046e4844b2ab57d4fc074f2c (patch) | |
tree | bc18bbca368b166802e60e22d9a3416e5ed104dd | |
parent | 13a369ce8d13cba304e9920d1dc445d6f74cca76 (diff) | |
download | scala-f72b4dfe467a967f046e4844b2ab57d4fc074f2c.tar.gz scala-f72b4dfe467a967f046e4844b2ab57d4fc074f2c.tar.bz2 scala-f72b4dfe467a967f046e4844b2ab57d4fc074f2c.zip |
-rw-r--r-- | src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala | 8 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/models/SemanticTokens.scala | 7 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/symtab/Symbols.scala | 20 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/transform/Mixin.scala | 13 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Namers.scala | 33 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/RefChecks.scala | 53 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/typechecker/Typers.scala | 18 | ||||
-rw-r--r-- | test/files/neg/bug521.check | 4 | ||||
-rw-r--r-- | test/files/neg/bug562.check | 2 | ||||
-rw-r--r-- | test/files/neg/bug565.check | 1 | ||||
-rw-r--r-- | test/files/neg/bug630.check | 2 |
12 files changed, 83 insertions, 80 deletions
diff --git a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala index 3dc6143a8c..00f1763945 100644 --- a/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala +++ b/src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala @@ -8,7 +8,7 @@ package scala.tools.nsc.backend.icode.analysis import scala.collection.mutable.{Map, HashMap} - +import scala.tools.nsc.symtab.Flags.DEFERRED /** * A modified copy-propagation like analysis. It * is augmented with a record-like value which is used @@ -446,7 +446,11 @@ abstract class CopyPropagation { /** Is `m' a pure method? */ final def isPureMethod(m: Symbol): Boolean = - m.isGetter; + // MO: I added !m.hasFlag(DEFERRED) in a refactoring where + // getters now can be abstract whereas before they could not. + // Adding the condition thus keeps the old behavior. + // todo: review whether this is correct, or whether abstract getters should be included. + m.isGetter && !m.hasFlag(DEFERRED); final override def toString(): String = { var res = ""; diff --git a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala index 794820ccab..158bc207eb 100644 --- a/src/compiler/scala/tools/nsc/models/SemanticTokens.scala +++ b/src/compiler/scala/tools/nsc/models/SemanticTokens.scala @@ -10,6 +10,7 @@ import scala.collection.mutable.{HashMap,HashSet} import scala.tools.nsc.Global import scala.tools.nsc.symtab.{Flags,Names} import scala.tools.nsc.util.{NameTransformer,Position,SourceFile} +import scala.tools.nsc.symtab.Flags.DEFERRED class SemanticTokens(val compiler: Global) { import compiler._ @@ -211,7 +212,11 @@ class SemanticTokens(val compiler: Global) { build(tree.impl.parents) build(tree.impl.body) case tree: ValOrDefDef => - if (!tree.symbol.hasFlag(Flags.ACCESSOR)) { + if (!tree.symbol.hasFlag(Flags.ACCESSOR) || tree.symbol.hasFlag(DEFERRED)) { + // MO: I added !tree.symbol.hasFlag(DEFERRED) in a refactoring where + // getters now can be abstract whereas before they could not. + // Adding the condition thus keeps the old behavior. + // todo: review whether this is correct, or whether abstract getters should be included. { val pos : Int = if (tree.name.toString().equals("<init>")) NoPos else eatKeywords(unit.source, tree.pos); diff --git a/src/compiler/scala/tools/nsc/symtab/Symbols.scala b/src/compiler/scala/tools/nsc/symtab/Symbols.scala index a6ab145e65..4ddb5689c3 100644 --- a/src/compiler/scala/tools/nsc/symtab/Symbols.scala +++ b/src/compiler/scala/tools/nsc/symtab/Symbols.scala @@ -761,13 +761,15 @@ trait Symbols requires SymbolTable { sym } - /** The getter of this value definition in class `base', or NoSymbol if + /** The getter of this value or setter definition in class `base', or NoSymbol if * none exists. */ - final def getter(base: Symbol): Symbol = - base.info.decl(nme.getterName(name)) filter (.hasFlag(ACCESSOR)) + final def getter(base: Symbol): Symbol = { + val getterName = if (isSetter) nme.setterToGetter(name) else nme.getterName(name) + base.info.decl(getterName) filter (.hasFlag(ACCESSOR)) + } - /** The setter of this value definition, or NoSymbol if none exists */ + /** The setter of this value or getter definition, or NoSymbol if none exists */ final def setter(base: Symbol): Symbol = base.info.decl(nme.getterToSetter(nme.getterName(name))) filter (.hasFlag(ACCESSOR)) @@ -791,7 +793,7 @@ trait Symbols requires SymbolTable { def expandName(base: Symbol): unit = if (this.isTerm && this != NoSymbol && !hasFlag(EXPANDEDNAME)) { setFlag(EXPANDEDNAME) - if (hasFlag(ACCESSOR)) { + if (hasFlag(ACCESSOR) && !hasFlag(DEFERRED)) { accessed.expandName(base) } else if (hasGetter) { getter(owner).expandName(base) @@ -862,8 +864,12 @@ trait Symbols requires SymbolTable { * E.g. $eq => =. * If settings.uniquId adds id. */ - def nameString: String = - simpleName.decode + idString + def nameString: String = { + var s = simpleName.decode.toString + if (s endsWith nme.LOCAL_SUFFIX) + s = s.substring(0, s.length - nme.LOCAL_SUFFIX.length) + s + idString + } /** String representation of symbol's full name with <code>separator</code> * between class names. diff --git a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala index 2dd32c1641..44c53a31be 100644 --- a/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala +++ b/src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala @@ -71,9 +71,7 @@ abstract class ExplicitOuter extends InfoTransform with TransMatcher with Patter def transformInfo(sym: Symbol, tp: Type): Type = tp match { case MethodType(formals, restpe) => if (sym.owner.isTrait && ((sym hasFlag SUPERACCESSOR) || sym.isModule)) { // 5 - //Console.println("make not private: "+sym+" "+sym.owner)//debug sym.makeNotPrivate(sym.owner) - //Console.println("made not private: "+sym)//debug } if (sym.owner.isTrait && (sym hasFlag PROTECTED)) sym setFlag notPROTECTED // 6 if (sym.isClassConstructor && isInner(sym.owner)) // 1 diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala index 5476f558b9..ad0cc5d566 100644 --- a/src/compiler/scala/tools/nsc/transform/Mixin.scala +++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala @@ -128,14 +128,14 @@ abstract class Mixin extends InfoTransform { * always accessors and deferred. */ def newGetter(field: Symbol): Symbol = clazz.newMethod(field.pos, nme.getterName(field.name)) - .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | DEFERRED) + .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | lateDEFERRED) .setInfo(MethodType(List(), field.info)) /** Create a new setter. Setters are never private or local. They are * always accessors and deferred. */ def newSetter(field: Symbol): Symbol = clazz.newMethod(field.pos, nme.getterToSetter(nme.getterName(field.name))) - .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | DEFERRED) + .setFlag(field.flags & ~(PRIVATE | LOCAL) | ACCESSOR | lateDEFERRED) .setInfo(MethodType(List(field.info), UnitClass.tpe)) clazz.info // make sure info is up to date, so that implClass is set. @@ -214,7 +214,9 @@ abstract class Mixin extends InfoTransform { // For all members of a trait's interface do: for (val member <- mixinClass.info.decls.toList) { - if (member hasFlag ACCESSOR) { // mixin field accessors + if ((member hasFlag ACCESSOR) && + (!(member hasFlag DEFERRED) || (member hasFlag lateDEFERRED))) { + // mixin field accessors val member1 = addMember( clazz, member.cloneSymbol(clazz) @@ -486,7 +488,8 @@ abstract class Mixin extends InfoTransform { addDefDef(sym, vparamss => EmptyTree) } else if (!clazz.isTrait) { // if class is not a trait: - if (sym hasFlag ACCESSOR) { + if ((sym hasFlag ACCESSOR) && + (!(sym hasFlag DEFERRED) || (sym hasFlag lateDEFERRED))) { // add accessor definitions addDefDef(sym, vparams => { val accessedRef = sym.tpe match { @@ -498,9 +501,7 @@ abstract class Mixin extends InfoTransform { }) } else if (sym.isModule && !(sym hasFlag LIFTED | BRIDGE)) { // add modules - //Console.println("add module "+sym+sym.hasFlag(EXPANDEDNAME))//debug val vdef = gen.mkModuleVarDef(sym) - //Console.println("add module "+sym+sym.hasFlag(EXPANDEDNAME)+":"+vdef.symbol.tpe)//debug addDef(position(sym), vdef) addDef(position(sym), gen.mkModuleAccessDef(sym, vdef.symbol)) } else if (!sym.isMethod) { diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala index be1c97c8b4..e7e6a946a4 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala @@ -242,9 +242,8 @@ trait Namers requires Analyzer { finish case ValDef(mods, name, tp, rhs) => if (context.owner.isClass & (mods.flags & LOCAL) == 0) { - val accflags = - ((if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE else mods.flags | STABLE) | - (if ((mods.flags & DEFERRED) == 0) ACCESSOR else 0)); + val accflags = ACCESSOR | + (if ((mods.flags & MUTABLE) != 0) mods.flags & ~MUTABLE else mods.flags | STABLE) val getter = owner.newMethod(tree.pos, name) .setFlag(accflags) .setInfo(innerNamer.getterTypeCompleter(tree)); @@ -394,7 +393,6 @@ trait Namers requires Analyzer { val parents = typer.parentTypes(templ) map checkParent val decls = newScope; new Namer(context.make(templ, clazz, decls)).enterSyms(templ.body); - ClassInfoType(parents, decls, clazz) } @@ -597,9 +595,7 @@ trait Namers requires Analyzer { if (!sym.isValueParameter && !sym.isTypeParameterOrSkolem && (!sym.owner.isClass || sym.owner.isModuleClass || sym.owner.isAnonymousClass)) { context.error(sym.pos, - "only classes can have declared but undefined members" + - (if (!sym.isVariable) "" - else "\n(Note that variables need to be initialized to be defined)")); + "only classes can have declared but undefined members" + varNotice(sym)) sym.resetFlag(DEFERRED) } } @@ -654,5 +650,28 @@ trait Namers requires Analyzer { } abstract class TypeCompleter(val tree: Tree) extends LazyType + + /** The symbol that which this accessor represents (possibly in part). + * This is used for error messages, where we want to speak in terms + * of the actual declaration or definition, not in terms of the generated setters + * and getters */ + def underlying(member: Symbol) = + if (member hasFlag ACCESSOR) { + if (member hasFlag DEFERRED) { + val getter = if (member.isSetter) member.getter(member.owner) else member + val result = getter.owner.newValue(getter.pos, getter.name) + .setInfo(getter.tpe.resultType) + .setFlag(DEFERRED) + if (getter.setter(member.owner) != NoSymbol) result.setFlag(MUTABLE) + result + } else member.accessed + } else member + + /** An explanatory note to be added to error messages + * when there's a problem with abstract var defs */ + def varNotice(sym: Symbol) = + if (underlying(sym).isVariable) + "\n(Note that variables need to be initialized to be defined)" + else "" } diff --git a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala index 55d1511594..51a1f4ba23 100644 --- a/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala +++ b/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala @@ -80,15 +80,16 @@ abstract class RefChecks extends InfoTransform { val self = clazz.thisType - def infoString(sym: Symbol) = ( - sym.toString() + - (if (sym.owner == clazz) "" - else (sym.locationString + - (if (sym.isAliasType) ", which equals " + self.memberInfo(sym) - else if (sym.isAbstractType) " with bounds " + self.memberInfo(sym) - else if (sym.isTerm) " of type " + self.memberInfo(sym) - else ""))) - ); + def infoString(sym: Symbol) = { + val sym1 = analyzer.underlying(sym) + sym1.toString() + + (if (sym1.owner == clazz) "" + else (sym1.locationString + + (if (sym1.isAliasType) ", which equals " + self.memberInfo(sym1) + else if (sym1.isAbstractType) " with bounds " + self.memberInfo(sym1) + else if (sym1.isTerm) " of type " + self.memberInfo(sym1) + else ""))) + } def overridesType(tp1: Type, tp2: Type): boolean = Pair(tp1, tp2) match { case Pair(MethodType(List(), rtp1), PolyType(List(), rtp2)) => @@ -112,7 +113,7 @@ abstract class RefChecks extends InfoTransform { def overrideTypeError(): unit = { if (other.tpe != ErrorType && member.tpe != ErrorType) { - overrideError("has incompatible type "+member.tpe); + overrideError("has incompatible type "+analyzer.underlying(member).tpe); explainTypes(member.tpe, other.tpe); } } @@ -163,7 +164,8 @@ abstract class RefChecks extends InfoTransform { overrideError("needs `override' modifier"); } else if ((other hasFlag ABSOVERRIDE) && other.isIncompleteIn(clazz) && !(member hasFlag ABSOVERRIDE)) { overrideError("needs `abstract override' modifiers") - } else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && (other hasFlag ACCESSOR) && other.accessed.isVariable) { + } else if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) && + (other hasFlag ACCESSOR) && other.accessed.isVariable) { overrideError("cannot override a mutable variable") } else if (other.isStable && !member.isStable) { // (1.4) overrideError("needs to be an immutable value") @@ -198,29 +200,6 @@ abstract class RefChecks extends InfoTransform { 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) { - val member = clazz.tpe.member(other.name) filter - (sym => sym.owner != other.owner && - (sym.isType || (self.memberType(sym) matches self.memberType(other)))); - if (member hasFlag OVERLOADED) { - val alt1 = member.alternatives.head; - val alt2 = member.alternatives.tail.head; - val pos = if (alt1.owner == clazz) alt1.pos - else if (alt2.owner == clazz) alt2.pos - else clazz.pos; - unit.error(pos, - "ambiguous override: both " + infoString(alt1) + - "\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.isTrait) { def abstractClassError(mustBeMixin: boolean, msg: String): unit = { @@ -232,10 +211,8 @@ abstract class RefChecks extends InfoTransform { } for (val member <- clazz.tpe.members) if ((member hasFlag DEFERRED) && !(clazz hasFlag ABSTRACT)) { - abstractClassError(false, - infoString(member) + " is not defined" + - (if (member.isVariable || member.hasFlag(ACCESSOR)) - "\n(Note that variables need to be initialized to be defined)" else "")) + abstractClassError( + false, infoString(member) + " is not defined" + analyzer.varNotice(member)) } else if ((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)) { val other = member.superSymbol(clazz); abstractClassError(true, diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala index 1bfba3fc3c..01ddfae607 100644 --- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala +++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala @@ -674,17 +674,8 @@ trait Typers requires Analyzer { result } def setterDef: DefDef = { - var setter = value.owner.info.decl(nme.getterToSetter(getter.name)).filter( - .tpe.=:=(MethodType(List(value.tpe.resultType), UnitClass.tpe))); - // note can't use .suchThat(.isSetter) above, - // because generated setters of abstract variables are not setters in this sense. - if (setter hasFlag OVERLOADED) setter = setter.alternatives.head; - // we will get a double definition error later anyway! - - assert(setter != NoSymbol, getter);//debug - val result = atPos(vdef.pos)( - DefDef(setter, vparamss => + DefDef(getter.setter(value.owner), vparamss => if (mods hasFlag DEFERRED) EmptyTree else typed(Assign(Select(This(value.owner), value), Ident(vparamss.head.head))))) @@ -777,7 +768,8 @@ trait Typers requires Analyzer { alias = NoSymbol if (alias != NoSymbol) { var ownAcc = clazz.info.decl(name).suchThat(.hasFlag(PARAMACCESSOR)) - if (ownAcc hasFlag ACCESSOR) ownAcc = ownAcc.accessed + if ((ownAcc hasFlag ACCESSOR) && !(ownAcc hasFlag DEFERRED)) + ownAcc = ownAcc.accessed if (settings.debug.value) log("" + ownAcc + " has alias "+alias + alias.locationString);//debug ownAcc.asInstanceOf[TermSymbol].setAlias(alias) @@ -1555,14 +1547,14 @@ trait Typers requires Analyzer { newTyper(context.makeNewScope(tree, tree.symbol)).typedFunction(fun, mode, pt) case Assign(lhs, rhs) => - def isGetter(sym: Symbol) = sym.info match { + def mayBeVarGetter(sym: Symbol) = sym.info match { case PolyType(List(), _) => sym.owner.isClass && !sym.isStable case _: ImplicitMethodType => sym.owner.isClass && !sym.isStable case _ => false } val lhs1 = typed(lhs, EXPRmode | LHSmode, WildcardType) val varsym = lhs1.symbol - if (varsym != null && isGetter(varsym)) { + if (varsym != null && mayBeVarGetter(varsym)) { lhs1 match { case Select(qual, name) => typed( diff --git a/test/files/neg/bug521.check b/test/files/neg/bug521.check index 4a80997bde..fa2ddffbaf 100644 --- a/test/files/neg/bug521.check +++ b/test/files/neg/bug521.check @@ -1,14 +1,14 @@ bug521.scala:12 error: class PlainFile needs to be abstract, since method path in class AbstractFile of type => java.lang.String is not defined class PlainFile(val file : File) extends AbstractFile {} ^ -bug521.scala:21 error: error overriding value file in class PlainFile of type => java.io.File; +bug521.scala:21 error: error overriding value file in class PlainFile of type java.io.File; value file needs `override' modifier final class ZipArchive(val file : File, archive : ZipFile) extends PlainFile(file) { ^ bug521.scala:21 error: class ZipArchive needs to be abstract, since method path in class AbstractFile of type => java.lang.String is not defined final class ZipArchive(val file : File, archive : ZipFile) extends PlainFile(file) { ^ -bug521.scala:23 error: error overriding value path in class VirtualFile of type => java.lang.String; +bug521.scala:23 error: error overriding value path in class VirtualFile of type java.lang.String; method path needs to be an immutable value override def path = ""; ^ diff --git a/test/files/neg/bug562.check b/test/files/neg/bug562.check index 6654ee5ef9..2badbf31b4 100644 --- a/test/files/neg/bug562.check +++ b/test/files/neg/bug562.check @@ -1,4 +1,4 @@ -bug562.scala:10 error: error overriding value y in trait YYY of type => scala.Int; +bug562.scala:10 error: error overriding value y in trait YYY of type scala.Int; value y cannot override a value or variable definition in a trait (this is an implementation restriction) override val y = super.y; diff --git a/test/files/neg/bug565.check b/test/files/neg/bug565.check index 673e112058..572692064f 100644 --- a/test/files/neg/bug565.check +++ b/test/files/neg/bug565.check @@ -1,4 +1,5 @@ bug565.scala:2 error: only classes can have declared but undefined members +(Note that variables need to be initialized to be defined) var s0: String ^ one error found diff --git a/test/files/neg/bug630.check b/test/files/neg/bug630.check index 42fb6ccd05..400a714fd2 100644 --- a/test/files/neg/bug630.check +++ b/test/files/neg/bug630.check @@ -1,4 +1,4 @@ -bug630.scala:20 error: error overriding value foo in trait Bar of type => Req2; +bug630.scala:20 error: error overriding value foo in trait Bar of type Req2; object foo has incompatible type object Test.this.foo object foo extends Req1 ^ |