summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2006-09-19 10:48:26 +0000
committerMartin Odersky <odersky@gmail.com>2006-09-19 10:48:26 +0000
commitf72b4dfe467a967f046e4844b2ab57d4fc074f2c (patch)
treebc18bbca368b166802e60e22d9a3416e5ed104dd /src/compiler/scala/tools/nsc
parent13a369ce8d13cba304e9920d1dc445d6f74cca76 (diff)
downloadscala-f72b4dfe467a967f046e4844b2ab57d4fc074f2c.tar.gz
scala-f72b4dfe467a967f046e4844b2ab57d4fc074f2c.tar.bz2
scala-f72b4dfe467a967f046e4844b2ab57d4fc074f2c.zip
Diffstat (limited to 'src/compiler/scala/tools/nsc')
-rw-r--r--src/compiler/scala/tools/nsc/backend/icode/analysis/CopyPropagation.scala8
-rw-r--r--src/compiler/scala/tools/nsc/models/SemanticTokens.scala7
-rw-r--r--src/compiler/scala/tools/nsc/symtab/Symbols.scala20
-rw-r--r--src/compiler/scala/tools/nsc/transform/ExplicitOuter.scala2
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala13
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala33
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/RefChecks.scala53
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala18
8 files changed, 78 insertions, 76 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(