From 55e40e1fdf166bcc0a5048523af955bf22f24a79 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Wed, 8 Oct 2003 19:05:14 +0000 Subject: *** empty log message *** --- doc/reference/ScalaReference.tex | 77 ++++++++++++++-------- .../scala/collection/mutable/ObservableMap.scala | 6 +- .../scala/collection/mutable/ObservableSet.scala | 6 +- .../scala/collection/mutable/SynchronizedMap.scala | 8 +-- .../scala/collection/mutable/SynchronizedSet.scala | 10 +-- sources/scalac/ast/parser/Parser.java | 6 +- sources/scalac/ast/printer/TextTreePrinter.java | 2 +- sources/scalac/symtab/Modifiers.java | 8 ++- sources/scalac/symtab/Symbol.java | 7 +- sources/scalac/symtab/Type.java | 4 +- .../scalac/symtab/classfile/ClassfileParser.java | 4 +- sources/scalac/typechecker/Analyzer.java | 10 ++- sources/scalac/typechecker/RefCheck.java | 48 ++++++++++---- 13 files changed, 126 insertions(+), 70 deletions(-) diff --git a/doc/reference/ScalaReference.tex b/doc/reference/ScalaReference.tex index 109e8cb8d8..caec1424e7 100644 --- a/doc/reference/ScalaReference.tex +++ b/doc/reference/ScalaReference.tex @@ -1459,17 +1459,18 @@ Classes (\sref{sec:classes}) and objects A template defines the type signature, behavior and initial state of a class of objects or of a single object. Templates form part of instance creation expressions, class definitions, and object -definitions. A template -~\lstinline@$sc$ with $mc_1$ with $\ldots$ with $mc_n$ {$stats\,$}@~ consists of a -constructor invocation $sc$ which defines the template's {\em -superclass}, constructor invocations ~\lstinline@$mc_1 \commadots mc_n$@~ -$(n \geq 0)$, which define the template's {\em mixin classes}, and a -statement sequence $stats$ which contains additional member -definitions for the template. Superclass and mixin classes together -are called the {\em parent classes} of a template. The superclass of -a template must be a subtype of the superclass of each mixin class. -The {\em least proper supertype} of a template is the class type or -compound type (\sref{sec:compound-types}) consisting of the its parent classes. +definitions. A template ~\lstinline@$sc$ with $mc_1$ with $\ldots$ +with $mc_n$ {$stats\,$}@~ consists of a constructor invocation $sc$ +which defines the template's {\em superclass}, constructor invocations +~\lstinline@$mc_1 \commadots mc_n$@~ $(n \geq 0)$, which define the +template's {\em mixin classes}, and a statement sequence $stats$ which +contains additional member definitions for the template. Superclass +and mixin classes together are called the {\em parent classes} of a +template. They must be pairwise different. The superclass of a +template must be a subtype of the superclass of each mixin class. The +{\em least proper supertype} of a template is the class type or +compound type (\sref{sec:compound-types}) consisting of the its parent +classes. Member definitions define new members or overwrite members in the parent classes. If the template forms part of a class definition, @@ -1696,6 +1697,11 @@ labeled \code{protected}. \item If $M'$ is not an abstract member, then $M$ must be labeled \code{override}. +\item +If $M'$ is labelled \code{abstract} and \code{override}, and $M'$ is a +member of the static superclass of the class containing the definition +of $M$, then $M$ must also be labelled \code{abstract} and +\code{override}. \end{itemize} \example\label{ex:compound-a} @@ -1766,18 +1772,34 @@ The \code{override} modifier applies to class member definitions. It is mandatory for member definitions that override some other concrete member definition in a super- or mixin-class. If an \code{override} modifier is given, there must be at least one overridden member -definition. Furthermore, if the class containing the overriding -member is not abstract, and one of the overridden definitions is a -member of its superclass, that definition must be concrete -(\sref{sec:members}). +definition. + +The \code{override} modifier has an additional significance when +combined with the \code{abstract} modifier. That modifier combination +is only allowed in abstract classes. A member +labelled \code{abstract} and \code{override} must override some +member of the superclass of the class containing the definition. + +We call a member of a template {\em incomplete} if it is either +abstract (i.e.\ defined by a declaration), or it is labelled +\code{abstract} and \code{override} and it overrides an incomplete +member of the template's superclass. + +Note that the \code{abstract override} modifier combination does not +influence the concept whether a member is concrete or +abstract. A member for which only a declaration is given is abstract, +whereas a member for which a full definition is given is concrete. + \item The \code{abstract} modifier is used in class definitions. It is -mandatory if the class has abstract members, or if the class has -members labeled \code{override} which override only abstract members -in a parent class. Classes with \code{abstract} members +mandatory if the class has incomplete members. Abstract classes cannot be instantiated (\sref{sec:inst-creation}) with a constructor invocation unless followed by mixin constructors or statements which override all abstract members of the class. + +The \code{abstract} modifier can also be used in conjunction with +\code{override} for class member definitions. In that case the meaning +of the previous discussion applies. \item The \code{final} modifier applies to class member definitions and to class definitions. A \code{final} class member definition may not be @@ -2345,21 +2367,20 @@ If the expression's expected type is a singleton type, or \lstinline@$C$.this@ occurs as the prefix of a selection, its type is \lstinline@$C$.this.type@, otherwise it is the self type of class $C$. -A reference \lstinline@super.$m$@ in a template refers to the definition of -$m$ in the actual superclass (\sref{sec:base-classes}) of the -template. A reference \lstinline@$C$.super.$m$@ refers to the definition of -$m$ in the actual superclass of the innermost enclosing class or -object definition named $C$ which encloses the reference. The -definition referred to by \code{super} or \lstinline@$C$.super@ must be -concrete, or the template containing the reference must contain a -definition which has an \code{override} modifier and which overrides -$m$. +A reference \lstinline@super.$m$@ in a template refers to the +definition of $m$ in the actual superclass (\sref{sec:base-classes}) +of the template. A reference \lstinline@$C$.super.$m$@ refers to the +definition of $m$ in the actual superclass of the innermost enclosing +class or object definition named $C$ which encloses the reference. The +definition $m$ referred to via \code{super} or \lstinline@$C$.super@ +must be concrete, or the template containing the reference must have an +incomplete (\sref{sec:modifiers}) member $m'$ which overrides $m$. The \code{super} prefix may be followed by a mixin qualifier \lstinline@[$M\,$]@, as in \lstinline@$C$.super[$M\,$].$x$@. This is called a {\em mixin super reference}. In this case, the reference is to the member of $x$ in the (first) mixin class of $C$ whose simple name -is $M$. +is $M$. That member may not be abstract. \example\label{ex:super} Consider the following class definitions diff --git a/sources/scala/collection/mutable/ObservableMap.scala b/sources/scala/collection/mutable/ObservableMap.scala index 0739a53062..52de275828 100644 --- a/sources/scala/collection/mutable/ObservableMap.scala +++ b/sources/scala/collection/mutable/ObservableMap.scala @@ -22,7 +22,7 @@ abstract class ObservableMap[A, B, This <: ObservableMap[A, B, This]]: This extends scala.collection.mutable.Map[A, B] with Publisher[ObservableUpdate[Pair[A, B]] with Undo, This] { - override def update(key: A, value: B): Unit = get(key) match { + abstract override def update(key: A, value: B): Unit = get(key) match { case None => super.update(key, value); publish(new Inclusion(Pair(key, value)) with Undo { def undo = -=(key); @@ -33,7 +33,7 @@ abstract class ObservableMap[A, B, This <: ObservableMap[A, B, This]]: This }); } - override def -=(key: A): Unit = get(key) match { + abstract override def -=(key: A): Unit = get(key) match { case None => case Some(old) => super.-=(key); publish(new Removal(Pair(key, old)) with Undo { @@ -41,7 +41,7 @@ abstract class ObservableMap[A, B, This <: ObservableMap[A, B, This]]: This }); } - override def clear: Unit = { + abstract override def clear: Unit = { super.clear; publish(new Reset() with Undo { def undo = error("cannot undo"); }); } diff --git a/sources/scala/collection/mutable/ObservableSet.scala b/sources/scala/collection/mutable/ObservableSet.scala index 7b09759b6e..e3ec93ad05 100644 --- a/sources/scala/collection/mutable/ObservableSet.scala +++ b/sources/scala/collection/mutable/ObservableSet.scala @@ -21,17 +21,17 @@ abstract class ObservableSet[A, This <: ObservableSet[A, This]]: This extends scala.collection.mutable.Set[A] with Publisher[ObservableUpdate[A] with Undo, This] { - override def +=(elem: A): Unit = if (!contains(elem)) { + abstract override def +=(elem: A): Unit = if (!contains(elem)) { super.+=(elem); publish(new Inclusion(elem) with Undo { def undo = -=(elem); }); } - override def -=(elem: A): Unit = if (contains(elem)) { + abstract override def -=(elem: A): Unit = if (contains(elem)) { super.-=(elem); publish(new Removal(elem) with Undo { def undo = +=(elem); }); } - override def clear: Unit = { + abstract override def clear: Unit = { super.clear; publish(new Reset() with Undo { def undo = error("cannot undo"); }); } diff --git a/sources/scala/collection/mutable/SynchronizedMap.scala b/sources/scala/collection/mutable/SynchronizedMap.scala index 435caa0526..28e9f1707c 100644 --- a/sources/scala/collection/mutable/SynchronizedMap.scala +++ b/sources/scala/collection/mutable/SynchronizedMap.scala @@ -18,11 +18,11 @@ package scala.collection.mutable; */ trait SynchronizedMap[A, B] extends scala.collection.mutable.Map[A, B] with Monitor { - override def size: Int = synchronized { + abstract override def size: Int = synchronized { super.size; } - override def get(key: A): Option[B] = synchronized { + abstract override def get(key: A): Option[B] = synchronized { super.get(key); } @@ -58,11 +58,11 @@ trait SynchronizedMap[A, B] extends scala.collection.mutable.Map[A, B] with Moni super.toList; } - override def update(key: A, value: B): Unit = synchronized { + abstract override def update(key: A, value: B): Unit = synchronized { super.update(key, value); } - override def -=(key: A): Unit = synchronized { + abstract override def -=(key: A): Unit = synchronized { super.-=(key); } diff --git a/sources/scala/collection/mutable/SynchronizedSet.scala b/sources/scala/collection/mutable/SynchronizedSet.scala index 37344a2020..26a1c68fec 100644 --- a/sources/scala/collection/mutable/SynchronizedSet.scala +++ b/sources/scala/collection/mutable/SynchronizedSet.scala @@ -18,7 +18,7 @@ package scala.collection.mutable; */ trait SynchronizedSet[A] extends scala.collection.mutable.Set[A] with Monitor { - override def size: Int = synchronized { + abstract override def size: Int = synchronized { super.size } @@ -26,11 +26,11 @@ trait SynchronizedSet[A] extends scala.collection.mutable.Set[A] with Monitor { super.isEmpty } - override def contains(elem: A) = synchronized { + abstract override def contains(elem: A) = synchronized { super.contains(elem); } - override def +=(elem: A): Unit = synchronized { + abstract override def +=(elem: A): Unit = synchronized { super.+=(elem); } @@ -42,7 +42,7 @@ trait SynchronizedSet[A] extends scala.collection.mutable.Set[A] with Monitor { super.incl(that); } - override def -=(elem: A): Unit = synchronized { + abstract override def -=(elem: A): Unit = synchronized { super.-=(elem); } @@ -58,7 +58,7 @@ trait SynchronizedSet[A] extends scala.collection.mutable.Set[A] with Monitor { super.intersect(that); } - override def clear: Unit = synchronized { + abstract override def clear: Unit = synchronized { super.clear; } diff --git a/sources/scalac/ast/parser/Parser.java b/sources/scalac/ast/parser/Parser.java index 00128c52fb..73ca7fc747 100644 --- a/sources/scalac/ast/parser/Parser.java +++ b/sources/scalac/ast/parser/Parser.java @@ -1367,7 +1367,7 @@ public class Parser implements Tokens { int mod; switch (s.token) { case ABSTRACT: - mod = Modifiers.ABSTRACTCLASS; + mod = Modifiers.ABSTRACT; break; case FINAL: mod = Modifiers.FINAL; @@ -1404,7 +1404,7 @@ public class Parser implements Tokens { int mod; switch (s.token) { case ABSTRACT: - mod = Modifiers.ABSTRACTCLASS; + mod = Modifiers.ABSTRACT; break; case FINAL: mod = Modifiers.FINAL; @@ -1685,7 +1685,7 @@ public class Parser implements Tokens { case CASECLASS: case TRAIT: if (s.token == CASECLASS) mods |= Modifiers.CASE; - else if (s.token == TRAIT) mods |= Modifiers.TRAIT | Modifiers.ABSTRACTCLASS; + else if (s.token == TRAIT) mods |= Modifiers.TRAIT | Modifiers.ABSTRACT; do { s.nextToken(); ts.append(classDef(mods)); diff --git a/sources/scalac/ast/printer/TextTreePrinter.java b/sources/scalac/ast/printer/TextTreePrinter.java index 53b48c8a41..ac461d667d 100644 --- a/sources/scalac/ast/printer/TextTreePrinter.java +++ b/sources/scalac/ast/printer/TextTreePrinter.java @@ -674,7 +674,7 @@ public class TextTreePrinter implements TreePrinter { } protected void printModifiers(int flags) { - if ((flags & Modifiers.ABSTRACTCLASS) != 0) { + if ((flags & Modifiers.ABSTRACT) != 0) { print(KW_ABSTRACT); print(Text.Space); } diff --git a/sources/scalac/symtab/Modifiers.java b/sources/scalac/symtab/Modifiers.java index cc9111887a..292eb28bbc 100644 --- a/sources/scalac/symtab/Modifiers.java +++ b/sources/scalac/symtab/Modifiers.java @@ -19,7 +19,9 @@ public interface Modifiers { int SEALED = 0x00000010; int OVERRIDE = 0x00000020; int CASE = 0x00000040; - int ABSTRACTCLASS = 0x00000080; // abstract class + int ABSTRACT = 0x00000080; // abstract class, or used in conjunction + // with abstract override. + // Note difference to DEFERRED! int DEF = 0x00000100; // a def parameter int REPEATED = 0x00000200; // a repeated parameter @@ -69,7 +71,9 @@ public interface Modifiers { public static class Helper { public static boolean isAbstract(int flags) { - return (flags & (DEFERRED | ABSTRACTCLASS)) != 0; + // todo: ABSTRACT and DEFERRED should be separated. + return (flags & DEFERRED) != 0 || + (flags & (ABSTRACT | OVERRIDE)) == ABSTRACT; } public static boolean isFinal(int flags) { diff --git a/sources/scalac/symtab/Symbol.java b/sources/scalac/symtab/Symbol.java index 4b710248c6..3303edac5f 100644 --- a/sources/scalac/symtab/Symbol.java +++ b/sources/scalac/symtab/Symbol.java @@ -328,10 +328,15 @@ public abstract class Symbol implements Modifiers, Kinds { public final boolean isAbstractClass() { preInitialize(); - return (flags & ABSTRACTCLASS) != 0 && + return kind == CLASS && (flags & ABSTRACT) != 0 && this != Global.instance.definitions.ARRAY_CLASS; } + public final boolean isAbstractOverride() { + preInitialize(); + return (flags & (ABSTRACT | OVERRIDE)) == (ABSTRACT | OVERRIDE); + } + /* Does this symbol denote an anonymous class? */ public final boolean isAnonymousClass() { return isClass() && name.startsWith(Names.ANON_CLASS_NAME); diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index fac8f18f48..1532d9c0e6 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -157,7 +157,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { ExtCompoundType res = new ExtCompoundType(parts, members); res.tsym = new ClassSymbol( Position.FIRSTPOS, Names.COMPOUND_NAME.toTypeName(), Symbol.NONE, - SYNTHETIC | ABSTRACTCLASS); + SYNTHETIC | ABSTRACT); res.tsym.setInfo(res); res.tsym.primaryConstructor().setInfo( Type.MethodType(Symbol.EMPTY_ARRAY, Type.NoType)); @@ -590,7 +590,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { case TypeRef(_, Symbol sym, _): return sym.kind == CLASS && ((sym.flags & JAVA) != 0 || - (sym.flags & (TRAIT | ABSTRACTCLASS)) == 0); + (sym.flags & (TRAIT | ABSTRACT)) == 0); default: return false; } diff --git a/sources/scalac/symtab/classfile/ClassfileParser.java b/sources/scalac/symtab/classfile/ClassfileParser.java index 28f31c3647..9debd17b0f 100644 --- a/sources/scalac/symtab/classfile/ClassfileParser.java +++ b/sources/scalac/symtab/classfile/ClassfileParser.java @@ -86,7 +86,7 @@ public class ClassfileParser implements ClassfileConstants { // todo: correct flag transition c.flags = transFlags(flags); if ((c.flags & Modifiers.DEFERRED) != 0) - c.flags = c.flags & ~Modifiers.DEFERRED | Modifiers.ABSTRACTCLASS; + c.flags = c.flags & ~Modifiers.DEFERRED | Modifiers.ABSTRACT; Type supertpe = readClassType(in.nextChar()); Type[] basetpes = new Type[in.nextChar() + 1]; this.locals = new Scope(); @@ -145,7 +145,7 @@ public class ClassfileParser implements ClassfileConstants { if ((flags & 0x0010) != 0) res |= Modifiers.FINAL; if ((flags & 0x0200) != 0) - res |= Modifiers.INTERFACE | Modifiers.TRAIT | Modifiers.ABSTRACTCLASS; + res |= Modifiers.INTERFACE | Modifiers.TRAIT | Modifiers.ABSTRACT; return res | Modifiers.JAVA; } diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index 3bec1700e2..fb5ef34201 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -297,7 +297,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * - symbols with `override' modifier override some other symbol. */ void validate(Symbol sym) { - if ((sym.flags & ABSTRACTCLASS) != 0 && sym.kind != CLASS) { + if ((sym.flags & (ABSTRACT | OVERRIDE)) == ABSTRACT && + sym.kind != CLASS) { error(sym.pos, "`abstract' modifier can be used only for classes; " + "\nit should be omitted for abstract members"); } @@ -340,6 +341,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { * statement sequence. * - self-type of current class is a subtype of self-type of each parent class. * - parent constructors do not refer to value parameters of class. + * - no two parents define same symbol. */ void validateParentClasses(Tree[] constrs, Type[] parents, Type selfType) { for (int i = 0; i < parents.length; i++) { @@ -379,6 +381,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { selfType + " does not conform to " + parents[i] + "'s selftype " + parents[i].instanceType()); } + for (int j = 0; j < i; j++) { + if (parents[i].symbol() == parents[j].symbol()) + error(constrs[i].pos, parents[i].symbol() + " is inherited twice"); + } } } @@ -721,7 +727,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if (!clazz.primaryConstructor().isInitialized()) clazz.primaryConstructor().setInfo(new LazyTreeType(tree)); if ((mods & CASE) != 0) { - if ((mods & ABSTRACTCLASS) == 0) { + if ((mods & ABSTRACT) == 0) { // enter case constructor method. Symbol cf = TermSymbol.define( tree.pos, name.toTermName(), owner, diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index 799de7a290..8c87e28a3c 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -57,6 +57,12 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { // Override checking ------------------------------------------------------------ + static boolean isIncomplete(Symbol sym) { + return sym.isDeferred() || + sym.isAbstractOverride() && + isIncomplete(sym.overriddenSymbol(sym.owner().parents()[0])); + } + /** 1. Check all members of class `clazz' for overriding conditions. * 2. Check that only abstract classes have deferred members* * 3. Check that every member with an `override' modifier @@ -82,13 +88,16 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { if (i < 0) { unit.error(sym.pos, sym + " overrides nothing"); sym.flags &= ~OVERRIDE; - } else if (clazz.kind == CLASS && - (clazz.flags & ABSTRACTCLASS) == 0) { + } else if (sym.isAbstractOverride()) { Symbol sup = sym.overriddenSymbol(parents[0]); - if (sup.kind != NONE && (sup.flags & DEFERRED) != 0) { + if (sup.kind == NONE) { + unit.error(sym.pos, sym + " does not override a superclass member"); + } else if (clazz.kind == CLASS && + (clazz.flags & ABSTRACT) == 0 && + isIncomplete(sup)) { abstractClassError( clazz, sym + sym.locationString() + - " is marked `override', but overrides an abstract member of the superclass " + parents[0]); + " is marked `abstract' and `override' and overrides an incomplete superclass member in " + parents[0]); } } } @@ -134,7 +143,7 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { checkOverride(pos, clazz, member, other); } } - if (clazz.kind == CLASS && (clazz.flags & ABSTRACTCLASS) == 0) { + if (clazz.kind == CLASS && (clazz.flags & ABSTRACT) == 0) { if ((member.flags & DEFERRED) != 0) { abstractClassError( clazz, @@ -160,7 +169,7 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { unit.error(clazz.pos, "object creation impossible, since " + msg); else unit.error(clazz.pos, clazz + " needs to be abstract, since " + msg); - clazz.flags |= ABSTRACTCLASS; + clazz.flags |= ABSTRACT; } @@ -177,6 +186,9 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { * or M is a type alias or class which conforms to O's bounds. * 7. If O and M are values, then M's type is a subtype of O's type. * 8. If O is an immutable value, then so is M. + * 9. If O is a member of the static superclass of the class in which + * M is defined, and O is labelled `abstract override', then + * M must be labelled `abstract override'. */ void checkOverride(int pos, Symbol clazz, Symbol member, Symbol other) { if (member.owner() == clazz) @@ -190,8 +202,15 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { overrideError(pos, member, other, "has weaker access privileges; it should not be protected"); } else if ((other.flags & FINAL) != 0) { overrideError(pos, member, other, "cannot override final member"); + } else if (other.kind == CLASS) { + overrideError(pos, member, other, "cannot override a class"); } else if ((other.flags & DEFERRED) == 0 && ((member.flags & OVERRIDE) == 0)) { overrideError(pos, member, other, "needs `override' modifier"); + } else if (other.isAbstractOverride() && + !member.isAbstractOverride() && + member.owner() == clazz && + clazz.parents()[0].symbol().isSubClass(other.owner())) { + overrideError(pos, member, other, "needs `abstract' and `override' modifiers"); } else if (other.isStable() && !member.isStable()) { overrideError(pos, member, other, "needs to be an immutable value"); } else if ((member.flags & DEFERRED) == 0 && (other.flags & DEFERRED) == 0 && @@ -206,9 +225,6 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { Type self = clazz.thisType(); switch (other.kind) { - case CLASS: - overrideError(pos, member, other, "cannot override a class"); - break; case ALIAS: if (member.typeParams().length != 0) overrideError(pos, member, other, "may not be parameterized"); @@ -994,11 +1010,15 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { sym.flags |= ACCESSED; if (!TreeInfo.isSelf(qual, enclClass)) sym.flags |= SELECTOR; - if (qual instanceof Tree.Super && (sym.flags & DEFERRED) != 0) { - Symbol sym1 = enclClass.thisSym().info().lookup(sym.name); - if ((sym1.flags & OVERRIDE) == 0 || (sym1.flags & DEFERRED) != 0) - unit.error(tree.pos, - "symbol accessed from super may not be abstract"); + if ((sym.flags & DEFERRED) != 0) { + switch (qual) { + case Super(Name qualifier, Name mixin): + Symbol sym1 = enclClass.thisSym().info().lookup(sym.name); + if (mixin != TypeNames.EMPTY || !isIncomplete(sym1)) + unit.error( + tree.pos, + "symbol accessed from super may not be abstract"); + } } return elimTypeNode(super.transform(tree)); -- cgit v1.2.3