summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2008-02-22 13:14:54 +0000
committerMartin Odersky <odersky@gmail.com>2008-02-22 13:14:54 +0000
commit0c48c80ce9122ca765cd328bca210a985dc699dc (patch)
tree0e1c8788cd6ae99702b8b974001ecebdc31fc7ce
parentecca8e2e67426bb43ad01edba87400c0dbd5799c (diff)
downloadscala-0c48c80ce9122ca765cd328bca210a985dc699dc.tar.gz
scala-0c48c80ce9122ca765cd328bca210a985dc699dc.tar.bz2
scala-0c48c80ce9122ca765cd328bca210a985dc699dc.zip
disallow accesses of the form super.val; allow ...
disallow accesses of the form super.val; allow overriding vals in traits.
-rw-r--r--src/compiler/scala/tools/nsc/transform/Mixin.scala64
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala78
2 files changed, 81 insertions, 61 deletions
diff --git a/src/compiler/scala/tools/nsc/transform/Mixin.scala b/src/compiler/scala/tools/nsc/transform/Mixin.scala
index 0b377b49fe..cadc90a957 100644
--- a/src/compiler/scala/tools/nsc/transform/Mixin.scala
+++ b/src/compiler/scala/tools/nsc/transform/Mixin.scala
@@ -221,38 +221,44 @@ abstract class Mixin extends InfoTransform {
*/
def mixinTraitMembers(mixinClass: Symbol) {
// For all members of a trait's interface do:
+ def isOverridden(member: Symbol) =
+ member.overridingSymbol(clazz) != NoSymbol
for (val member <- mixinClass.info.decls.toList) {
if ((member hasFlag ACCESSOR) &&
(!(member hasFlag DEFERRED) || (member hasFlag lateDEFERRED))) {
- // mixin field accessors
- val member1 = addMember(
- clazz,
- member.cloneSymbol(clazz)
- setPos clazz.pos
- setFlag FINAL resetFlag (DEFERRED | lateDEFERRED))
- if (member.hasFlag(LAZY)) {
- var init = implClass(mixinClass).info.decl(member.name)
- assert(init != NoSymbol, "Could not find initializer for " + member.name)
- initializer(member1) = init
- }
- if (!member.isSetter)
- member.tpe match {
- case MethodType(List(), ConstantType(_)) =>
- // member is a constant; only getter is needed
- ;
- case MethodType(List(), TypeRef(_, tpeSym, _))
- if member.hasFlag(LAZY) && tpeSym == definitions.UnitClass =>
- // member is a lazy value of type unit. No field needed
- ;
- case _ =>
- // otherwise mixin a field as well
- addMember(clazz,
- clazz.newValue(member.pos, nme.getterToLocal(member.name))
- setFlag (LOCAL | PRIVATE | member.getFlag(MUTABLE | LAZY))
- setFlag (if (!member.hasFlag(STABLE)) MUTABLE else 0)
- setInfo member.tpe.resultType
- setAttributes member.attributes)
+ if (isOverridden(member))
+ if (settings.debug.value) println("!!! is overridden val: "+member)
+ else {
+ // mixin field accessors
+ val member1 = addMember(
+ clazz,
+ member.cloneSymbol(clazz)
+ setPos clazz.pos
+ setFlag FINAL resetFlag (DEFERRED | lateDEFERRED))
+ if (member.hasFlag(LAZY)) {
+ var init = implClass(mixinClass).info.decl(member.name)
+ assert(init != NoSymbol, "Could not find initializer for " + member.name)
+ initializer(member1) = init
}
+ if (!member.isSetter)
+ member.tpe match {
+ case MethodType(List(), ConstantType(_)) =>
+ // member is a constant; only getter is needed
+ ;
+ case MethodType(List(), TypeRef(_, tpeSym, _))
+ if member.hasFlag(LAZY) && tpeSym == definitions.UnitClass =>
+ // member is a lazy value of type unit. No field needed
+ ;
+ case _ =>
+ // otherwise mixin a field as well
+ addMember(clazz,
+ clazz.newValue(member.pos, nme.getterToLocal(member.name))
+ setFlag (LOCAL | PRIVATE | member.getFlag(MUTABLE | LAZY))
+ setFlag (if (!member.hasFlag(STABLE)) MUTABLE else 0)
+ setInfo member.tpe.resultType
+ setAttributes member.attributes)
+ }
+ }
} else if (member hasFlag SUPERACCESSOR) { // mixin super accessors
val member1 = addMember(clazz, member.cloneSymbol(clazz)) setPos clazz.pos
assert(member1.alias != NoSymbol, member1)
@@ -613,7 +619,7 @@ abstract class Mixin extends InfoTransform {
// if current class is a trait interface, add an abstract method for accessor `sym'
addDefDef(sym, vparamss => EmptyTree)
} else if (!clazz.isTrait) {
- // if class is not a trait:
+ // if class is not a trait add accessor definitions
if ((sym hasFlag ACCESSOR) &&
(!(sym hasFlag DEFERRED) || (sym hasFlag lateDEFERRED))) {
// add accessor definitions
diff --git a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
index 821c0e6b4d..db98d44e76 100644
--- a/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/SuperAccessors.scala
@@ -84,6 +84,48 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
}
+ private def transformSuperSelect(tree: Tree) = tree match {
+ case Select(sup @ Super(_, mix), name) =>
+ val sym = tree.symbol
+ val clazz = sup.symbol
+ if (sym.isDeferred) {
+ val member = sym.overridingSymbol(clazz);
+ if (mix != nme.EMPTY.toTypeName || member == NoSymbol ||
+ !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)))
+ unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+
+ "unless it is overridden by a member declared `abstract' and `override'");
+ }
+ if (tree.isTerm && mix == nme.EMPTY.toTypeName &&
+ (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) {
+ val supername = nme.superName(sym.name)
+ var superAcc = clazz.info.decl(supername).suchThat(_.alias == sym)
+ if (superAcc == NoSymbol) {
+ if (settings.debug.value) log("add super acc " + sym + sym.locationString + " to `" + clazz);//debug
+ superAcc =
+ clazz.newMethod(tree.pos, supername)
+ .setFlag(SUPERACCESSOR | PRIVATE)
+ .setAlias(sym)
+ var superAccTpe = clazz.thisType.memberType(sym)
+ if (sym.isModule && !sym.isMethod) {
+ // the super accessor always needs to be a method. See #231
+ superAccTpe = PolyType(List(), superAccTpe)
+ }
+ superAcc.setInfo(superAccTpe.cloneInfo(superAcc))
+ //println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG
+ clazz.info.decls enter superAcc;
+ accDefBuf(clazz) += typed(DefDef(superAcc, vparamss => EmptyTree))
+ }
+ atPos(sup.pos) {
+ Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe;
+ }
+ } else {
+ tree
+ }
+ case _ =>
+ assert(tree.tpe.isError, tree)
+ tree
+ }
+
override def transform(tree: Tree): Tree = try { tree match {
case ClassDef(_, _, _, _) =>
checkCompanionNameClashes(tree.symbol)
@@ -131,7 +173,7 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
if (settings.debug.value)
Console.println("alias replacement: " + tree + " ==> " + result);//debug
- transform(result)
+ transformSuperSelect(result)
} else {
if (needsProtectedAccessor(sym, tree.pos)) {
if (settings.debug.value) log("Adding protected accessor for " + tree);
@@ -141,38 +183,10 @@ abstract class SuperAccessors extends transform.Transform with transform.TypingT
}
case Select(sup @ Super(_, mix), name) =>
val sym = tree.symbol
- val clazz = sup.symbol
- if (sym.isDeferred) {
- val member = sym.overridingSymbol(clazz);
- if (mix != nme.EMPTY.toTypeName || member == NoSymbol ||
- !((member hasFlag ABSOVERRIDE) && member.isIncompleteIn(clazz)))
- unit.error(tree.pos, ""+sym+sym.locationString+" is accessed from super. It may not be abstract "+
- "unless it is overridden by a member declared `abstract' and `override'");
+ if (sym.isValue && !sym.isMethod || sym.hasFlag(ACCESSOR)) {
+ unit.error(tree.pos, "super may be not be used on "+sym)
}
- if (tree.isTerm && mix == nme.EMPTY.toTypeName &&
- (clazz.isTrait || clazz != currentOwner.enclClass || !validCurrentOwner)) {
- val supername = nme.superName(sym.name)
- var superAcc = clazz.info.decl(supername).suchThat(_.alias == sym)
- if (superAcc == NoSymbol) {
- if (settings.debug.value) log("add super acc " + sym + sym.locationString + " to `" + clazz);//debug
- superAcc =
- clazz.newMethod(tree.pos, supername)
- .setFlag(SUPERACCESSOR | PRIVATE)
- .setAlias(sym)
- var superAccTpe = clazz.thisType.memberType(sym)
- if (sym.isModule && !sym.isMethod) {
- // the super accessor always needs to be a method. See #231
- superAccTpe = PolyType(List(), superAccTpe)
- }
- superAcc.setInfo(superAccTpe.cloneInfo(superAcc))
- //println("creating super acc "+superAcc+":"+superAcc.tpe)//DEBUG
- clazz.info.decls enter superAcc;
- accDefBuf(clazz) += typed(DefDef(superAcc, vparamss => EmptyTree))
- }
- atPos(sup.pos) {
- Select(gen.mkAttributedThis(clazz), superAcc) setType tree.tpe;
- }
- } else tree
+ transformSuperSelect(tree)
case TypeApply(sel @ Select(qual, name), args) =>
val sym = tree.symbol