*** empty log message ***

git-svn-id: http://lampsvn.epfl.ch/svn-repos/scala/scala/trunk@3244 5e8d7ff9-d8ef-0310-90f0-a4852d11357a
This commit is contained in:
odersky 2004-06-03 12:33:10 +00:00
parent 3b72eb5544
commit 9fb513dafd
16 changed files with 250 additions and 87 deletions

View File

@ -201,20 +201,19 @@ Of course, a compiler is free (if it is moderately smart, even expected)
to recognize the special case of calling the \code{+} method over to recognize the special case of calling the \code{+} method over
integer arguments and to generate efficient inline code for it. integer arguments and to generate efficient inline code for it.
Control constructs such as \code{while} are also not primitive but are For efficiency and better error diagnostics the \code{while} loop is a
predefined functions in the standard Scala library. Here is the primitive construct in Scala. But in principle, it could have just as
definition of \code{while} in Scala. well been a predefined function. Here is a possible implementation of it:
\begin{lstlisting} \begin{lstlisting}
def while (def p: boolean) (def s: unit): unit = def While (def p: boolean) (def s: unit): unit =
if (p) { s ; while(p)(s) } if (p) { s ; While(p)(s) }
\end{lstlisting} \end{lstlisting}
The \code{while} function takes as first parameter a test function, The \code{While} function takes as first parameter a test function,
which takes no parameters and yields a boolean value. As second which takes no parameters and yields a boolean value. As second
parameter it takes a command function which also takes no parameters parameter it takes a command function which also takes no parameters
and yields a trivial result. \code{while} invokes the command function and yields a trivial result. \code{While} invokes the command function
as long as the test function yields true. Again, compilers are free to as long as the test function yields true.
pick specialized implementations of \code{while} that have the same
behavior as the invocation of the function given above.
\chapter{Programming with Actors and Messages} \chapter{Programming with Actors and Messages}
\label{chap:example-auction} \label{chap:example-auction}
@ -260,7 +259,7 @@ are defined in Figure~\ref{fig:simple-auction-msgs}.
class Auction(seller: Actor, minBid: int, closing: Date) extends Actor { class Auction(seller: Actor, minBid: int, closing: Date) extends Actor {
val timeToShutdown = 36000000; // msec val timeToShutdown = 36000000; // msec
val bidIncrement = 10; val bidIncrement = 10;
def run() = { override def run() = {
var maxBid = minBid - bidIncrement; var maxBid = minBid - bidIncrement;
var maxBidder: Actor = _; var maxBidder: Actor = _;
var running = true; var running = true;
@ -6546,7 +6545,7 @@ messages. A {\em message} in this context is an arbitrary object.
There is a special message \code{TIMEOUT} which is used to signal a There is a special message \code{TIMEOUT} which is used to signal a
time-out. time-out.
\begin{lstlisting} \begin{lstlisting}
case class TIMEOUT; case object TIMEOUT;
\end{lstlisting} \end{lstlisting}
Mailboxes implement the following signature. Mailboxes implement the following signature.
\begin{lstlisting} \begin{lstlisting}
@ -6737,7 +6736,7 @@ class Auction(seller: Process, minBid: int, closing: Date)
val delta = 10 // bid increment val delta = 10 // bid increment
\end{lstlisting} \end{lstlisting}
\begin{lstlisting} \begin{lstlisting}
def run = { override def run = {
var askedBid = minBid var askedBid = minBid
var maxBidder: Process = null var maxBidder: Process = null
while (true) { while (true) {
@ -6850,7 +6849,7 @@ class Bidder (auction: Process, minBid: int, maxBid: int)
} }
\end{lstlisting} \end{lstlisting}
\begin{lstlisting} \begin{lstlisting}
def run = { override def run = {
getAuctionStatus getAuctionStatus
if (nextBid != Unknown) bid if (nextBid != Unknown) bid
} }

View File

@ -762,12 +762,12 @@ transitive relation that satisfies the following conditions.
binding of $x$ in $T$ subsuming it, then $T$ conforms to the binding of $x$ in $T$ subsuming it, then $T$ conforms to the
compound type ~\lstinline@$T_1$ with $\ldots$ with $T_n$ {$R\,$}@. compound type ~\lstinline@$T_1$ with $\ldots$ with $T_n$ {$R\,$}@.
\item If \item If
$T'_i$ conforms to $T_i$ for $i = 1 \commadots n$ and $U$ conforms to $U'$ $T_i \equiv T'_i$ for $i = 1 \commadots n$ and $U$ conforms to $U'$
then the method type $(T_1 \commadots T_n) U$ conforms to then the method type $(T_1 \commadots T_n) U$ conforms to
$(T'_1 \commadots T'_n) U'$. $(T'_1 \commadots T'_n) U'$.
\item If, assuming \item If, assuming
$L'_1 \conforms a_1 \conforms U'_1 \commadots L'_n \conforms a_n \conforms U'_n$ $L'_1 \conforms a_1 \conforms U'_1 \commadots L'_n \conforms a_n \conforms U'_n$
one has $L_i \conforms L'_i$ and $U'_i \conforms U_i$ one has $L'_i \equiv L'_i$ and $U_i \equiv U'_i$
for $i = 1 \commadots n$, as well as $T \conforms T'$ then the polymorphic type for $i = 1 \commadots n$, as well as $T \conforms T'$ then the polymorphic type
$[a_1 >: L_1 <: U_1 \commadots a_n >: L_n <: U_n] T$ conforms to the polymorphic type $[a_1 >: L_1 <: U_1 \commadots a_n >: L_n <: U_n] T$ conforms to the polymorphic type
$[a_1 >: L'_1 <: U'_1 \commadots a_n >: L'_n <: U'_n] T'$. $[a_1 >: L'_1 <: U'_1 \commadots a_n >: L'_n <: U'_n] T'$.
@ -3776,7 +3776,9 @@ inserted by the compiler.
A view definition is a normal function definition with one value A view definition is a normal function definition with one value
parameter where the name of the defined function is \code{view}. parameter where the name of the defined function is \code{view}.
\example \example
The following defines an implicit coercion function from strings to lists of
characters.
\begin{lstlisting} \begin{lstlisting}
def view(xs: String): List[char] = def view(xs: String): List[char] =
@ -3784,9 +3786,6 @@ def view(xs: String): List[char] =
else xs.charAt(0) :: xs.substring(1); else xs.charAt(0) :: xs.substring(1);
\end{lstlisting} \end{lstlisting}
This defines an implicit coercion function from strings to lists of
characters.
\section{View Application} \section{View Application}
View applications are inserted implicitly in two situations. View applications are inserted implicitly in two situations.
@ -3814,7 +3813,7 @@ Searching a view which is applicable to an expression $e$ of type $T$
is a three-step process. is a three-step process.
\begin{enumerate} \begin{enumerate}
\item \item
First, the set $\VV$ of available views is determined. $\VV$ is the First, the set $\AA$ of available views is determined. $\AA$ is the
smallest set such that: smallest set such that:
\begin{enumerate} \begin{enumerate}
\item \item
@ -3849,7 +3848,7 @@ further view conversion of $e$ to the view's formal parameter type.
Likewise, a view's result type must conform to a given prototype Likewise, a view's result type must conform to a given prototype
directly, no second view conversion is allowed. directly, no second view conversion is allowed.
\item \item
It is an error is the set of applicable views $\BB$ is empty. For It is an error if the set of applicable views $\BB$ is empty. For
non-empty $\BB$, the view method which is most specific non-empty $\BB$, the view method which is most specific
(\sref{sec:overloaded-refs}) in $\BB$ is selected. It is an error if (\sref{sec:overloaded-refs}) in $\BB$ is selected. It is an error if
no most specific view exists, or if it is not unique. no most specific view exists, or if it is not unique.
@ -3920,16 +3919,16 @@ Implicit view parameters of a method or class are then taken as
available view methods in its body. available view methods in its body.
\example Consider the following definition of a trait \example Consider the following definition of a trait
\code{Comparable} and a view from strings to that trait.. \code{Comparable} and a view from strings to that trait.
\begin{lstlisting} \begin{lstlisting}
trait Comparable[a] { trait Comparable[a] {
def less (x: a): boolean def less(x: a): boolean
} }
object StringsAreComparable { object StringsAreComparable {
def view(x: String): Comparable[String] = new Comparable[String] { def view(x: String): Comparable[String] = new Comparable[String] {
def less (y: String) = x.compareTo(y) < 0 def less(y: String) = x.compareTo(y) < 0
} }
} }
\end{lstlisting} \end{lstlisting}
@ -4039,7 +4038,7 @@ allows the definition of conditional views.
list element type is also comparable. list element type is also comparable.
\begin{lstlisting} \begin{lstlisting}
def view[a <% Comparable[a]](x: List[a]): Comparable[List[a]] = def view[a <% Comparable[a]](xs: List[a]): Comparable[List[a]] =
new Comparable[List[a]] { new Comparable[List[a]] {
def less (ys: List[a]): boolean = def less (ys: List[a]): boolean =
!ys.isEmpty !ys.isEmpty
@ -4057,6 +4056,7 @@ type parameters are translated to implicit \code{view} arguments. In
this case, the \code{view} method over lists would receive the this case, the \code{view} method over lists would receive the
\code{view} method over list elements as implicit parameter. \code{view} method over list elements as implicit parameter.
\comment{
This opens up the risk of infinite instantiations because view methods This opens up the risk of infinite instantiations because view methods
are be passed to themselves as parameters. For instance, one might try are be passed to themselves as parameters. For instance, one might try
to define the following ``magic'' universal converter: to define the following ``magic'' universal converter:
@ -4086,6 +4086,7 @@ argument, either directly or indirectly. On the other hand,
contractive view methods may be passed to themselves as arguments. In the contractive view methods may be passed to themselves as arguments. In the
examples above this case arises if a list of lists of strings is seen examples above this case arises if a list of lists of strings is seen
as a \code{Comparable}. as a \code{Comparable}.
}
\chapter{Top-Level Definitions} \chapter{Top-Level Definitions}
\label{sec:topdefs} \label{sec:topdefs}

View File

@ -942,18 +942,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
val info = new LazyTreeType(tree); val info = new LazyTreeType(tree);
clazz.setInfo(info); clazz.setInfo(info);
modul.setInfo(info); modul.setInfo(info);
// !!! Unfortunately, this breaks separate compilation
// val lclass = modul.linkedClass();
// // Taken from SymbolLoader.initializeRoot()
// if (lclass != null) {
// if (lclass.rawInfo().isInstanceOf[SymbolLoader] &&
// !lclass.rawInfo().isInstanceOf[SourceCompleter]) {
// lclass.setInfo(Type.ErrorType);
// //val allConstr = lclass.allConstructors();
// //allConstr.setInfo(Type.ErrorType);
// //allConstr.flags = allConstr.flags | Modifiers.PRIVATE;
// }
// }
} }
enterSym(tree, modul) enterSym(tree, modul)
@ -1077,6 +1065,22 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
} }
} }
/*
def addOverloaded(tp: Type, sym: Symbol): Type = {
if (!sym.isPrivate()) {
val owner = sym.owner();
if (owner.kind == CLASS) {
for (p <- sym.owner().info.parents()) {
val sym1 = p.lookupNonPrivate(sym.name);
if (sym1.kind != NONE) {
}
}
}
}
}
*/
// Definining Symbols ------------------------------------------------------- // Definining Symbols -------------------------------------------------------
/** Define symbol associated with `tree' using given `unit' and `context'. /** Define symbol associated with `tree' using given `unit' and `context'.
@ -1176,6 +1180,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
owntype = makeMethodType(tparamSyms, vparamSyms, restype); owntype = makeMethodType(tparamSyms, vparamSyms, restype);
//System.out.println("methtype " + name + ":" + owntype);//DEBUG //System.out.println("methtype " + name + ":" + owntype);//DEBUG
sym.addInheritedOverloaded(owntype);
case Tree$ValDef(mods, name, _tpe, _rhs) => case Tree$ValDef(mods, name, _tpe, _rhs) =>
var tpe = _tpe; var tpe = _tpe;
@ -1207,6 +1212,7 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
owntype = owntype.deconst(); owntype = owntype.deconst();
} }
popContext(); popContext();
sym.addInheritedOverloaded(owntype);
} }
case Tree$AliasTypeDef(mods, name, tparams, _rhs) => case Tree$AliasTypeDef(mods, name, tparams, _rhs) =>
@ -1931,6 +1937,13 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
popContext(); popContext();
val templ1: Tree$Template = copy.Template(templ, parents, body1); val templ1: Tree$Template = copy.Template(templ, parents, body1);
templ1.setType(owner.getType()); templ1.setType(owner.getType());
// initialize all members; necessary to initialize overloaded symbols
val members = owner.members().iterator(false);
while (members.hasNext()) {
val sym = members.next();
sym.initialize();
//System.out.println(owner.toString() + " defines " + sym + ":" + sym.getType());//DEBUG
}
templ1 templ1
} }
@ -2199,7 +2212,22 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer(
val templ1: Tree$Template = transformTemplate(templ, sym.moduleClass()); val templ1: Tree$Template = transformTemplate(templ, sym.moduleClass());
if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType())) if (tpe1 != Tree.Empty && !templ1.getType().isSubType(tpe1.getType()))
error(tree.pos, "" + sym + " does not implement " + tpe1.getType()); error(tree.pos, "" + sym + " does not implement " + tpe1.getType());
copy.ModuleDef(tree, sym, tpe1, templ1)
/*
// !!! Unfortunately, this breaks separate compilation
val lclass = sym.linkedClass();
// Taken from SymbolLoader.initializeRoot()
if (lclass != null) {
if (lclass.rawInfo().isInstanceOf[SymbolLoader]) {
lclass.setInfo(Type.ErrorType);
val allConstr = lclass.allConstructors();
allConstr.setInfo(Type.ErrorType);
allConstr.flags = allConstr.flags | Modifiers.PRIVATE;
}
}
*/
copy.ModuleDef(tree, sym, tpe, templ1)
.setType(Type.NoType); .setType(Type.NoType);
case Tree$DefDef(_, name, tparams, vparams, tpe, rhs) => case Tree$DefDef(_, name, tparams, vparams, tpe, rhs) =>

View File

@ -391,7 +391,7 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
gen.mkNullLit(pos) gen.mkNullLit(pos)
} else { } else {
val v = bestView(vargs(0), vargs(1), Names.EMPTY); val v = bestView(vargs(0), vargs(1), Names.EMPTY);
if (v != null) { if (v != null && !v.locked) {
if (v.locked) { if (v.locked) {
error(pos, "recursive view instantiation of non-contractive " + error(pos, "recursive view instantiation of non-contractive " +
v.sym + v.sym.locationString() + " with type " + v.sym + v.sym.locationString() + " with type " +
@ -802,7 +802,9 @@ class Infer(global: scalac_Global, gen: TreeGen, make: TreeFactory) extends scal
while (!viewMeths.isEmpty && while (!viewMeths.isEmpty &&
!isApplicable(viewMeths.head.symtype, argtypes, pt, Names.EMPTY, false)) !isApplicable(viewMeths.head.symtype, argtypes, pt, Names.EMPTY, false))
viewMeths = viewMeths.tail; viewMeths = viewMeths.tail;
if (!viewMeths.isEmpty) true if (!viewMeths.isEmpty) {
true
}
// todo: remove // todo: remove
else { else {
val coerceMeth: Symbol = tp1.lookup(Names.coerce); val coerceMeth: Symbol = tp1.lookup(Names.coerce);

View File

@ -41,7 +41,7 @@ public interface Modifiers {
int PACKAGE = 0x00100000; // symbol is a java package. int PACKAGE = 0x00100000; // symbol is a java package.
int STABLE = 0x00800000; // functions that are assumed to be stable int STABLE = 0x00800000; // functions that are assumed to be stable
// (typically, access methods for valdefs) // (typically, access methods for valdefs)
int CAPTURED = 0x01000000; // variables is accessed from int CAPTURED = 0x01000000; // variables is accessed from
// nested function. Set by LambdaLift // nested function. Set by LambdaLift

View File

@ -1067,7 +1067,7 @@ public abstract class Symbol implements Modifiers, Kinds {
String name1 = name.toString(); String name1 = name.toString();
if (name1.endsWith(Names._EQ.toString())) if (name1.endsWith(Names._EQ.toString()))
name1 = name1.substring(0, name1.length() - Names._EQ.length()); name1 = name1.substring(0, name1.length() - Names._EQ.length());
return owner.info().lookup(Name.fromString(name1 + "$")); return owner.lookup(Name.fromString(name1 + "$"));
} }
/** The members of this class or module symbol /** The members of this class or module symbol
@ -1503,10 +1503,15 @@ public abstract class Symbol implements Modifiers, Kinds {
public Symbol overloadWith(Symbol that) { public Symbol overloadWith(Symbol that) {
assert isTerm() : Debug.show(this); assert isTerm() : Debug.show(this);
assert this.name == that.name : Debug.show(this) + " <> " + Debug.show(that); assert this.name == that.name : Debug.show(this) + " <> " + Debug.show(that);
assert this.owner == that.owner : Debug.show(this) + " != " + Debug.show(that); //assert this.owner == that.owner : Debug.show(this) + " != " + Debug.show(that);
assert this.isConstructor() == that.isConstructor(); assert this.isConstructor() == that.isConstructor();
int overflags = (this.flags & that.flags & (JAVA | ACCESSFLAGS | DEFERRED | PARAM | SYNTHETIC)) | int overflags;
((this.flags | that.flags) & ACCESSOR); //if (this.owner == that.owner)
overflags = (this.flags & that.flags &
(JAVA | ACCESSFLAGS | DEFERRED | PARAM | SYNTHETIC)) |
((this.flags | that.flags) & ACCESSOR);
// else // it's an inherited overloaded alternative
// overflags = this.flags & SOURCEFLAGS;
Symbol overloaded = (this.isConstructor()) Symbol overloaded = (this.isConstructor())
? this.constructorClass().newConstructor(this.constructorClass().pos, overflags) ? this.constructorClass().newConstructor(this.constructorClass().pos, overflags)
: owner.newTerm(pos, overflags, name, 0); : owner.newTerm(pos, overflags, name, 0);
@ -1638,6 +1643,62 @@ public abstract class Symbol implements Modifiers, Kinds {
public int tag() { public int tag() {
return name.toString().hashCode(); return name.toString().hashCode();
} }
public void addInheritedOverloaded(Type owntype) {
if (false && owner().kind == CLASS && !isConstructor() && owner().lookup(name) == this) {
// it's a class member which is not an overloaded alternative
Symbol sym = Type.lookupNonPrivate(owner().parents(), name);
if (sym.kind == VAL) {
Type symtype = owner.thisType().memberType(sym);
switch (symtype) {
case OverloadedType(Symbol[] alts, Type[] alttypes):
for (int i = 0; i < alts.length; i++)
addInheritedOverloaded(owntype, alts[i], alttypes[i]);
break;
default:
addInheritedOverloaded(owntype, sym, symtype);
}
}
}
}
private void addInheritedOverloaded(Type owntype, Symbol sym, Type symtype) {
if (!owntype.overrides(symtype)) {
System.out.println(owner() + " inherits overloaded: " + sym + ":" + symtype + sym.locationString());//debug
owner().members().lookupEntry(name).setSymbol(overloadWith(sym));
//System.out.println("type is now: " + owner().members().lookup(name).type());
}
}
public Type removeInheritedOverloaded(Type owntype) {
//assert name != Names.toString ||
// Global.instance.currentPhase.id != Global.instance.PHASE.UNCURRY.id();
switch (owntype) {
case OverloadedType(Symbol[] alts, Type[] alttypes):
int n = 0;
for (int i = 0; i < alts.length; i++)
if (alts[i].owner() == owner()) n++;
if (n < alts.length) {
Symbol[] alts1 = new Symbol[n];
Type[] alttypes1 = new Type[n];
int j = 0;
for (int i = 0; i < alts.length; i++) {
if (alts[i].owner() == owner()) {
alts1[j] = alts[i];
alttypes1[j] = alttypes[i];
j++;
} else {
System.out.println("removing inherited alternatve " + alts[i] + ":" + alttypes[i]);//debug
}
}
return Type.OverloadedType(alts1, alttypes1);
} else {
return owntype;
}
default:
return owntype;
}
}
} }
/** A class for term symbols /** A class for term symbols

View File

@ -197,7 +197,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags {
} }
public static Type typeRef(Type pre, Symbol sym, Type[] args) { public static Type typeRef(Type pre, Symbol sym, Type[] args) {
if (!pre.isLegalPrefix() && !pre.isError()) if (sym.kind == TYPE && !pre.isLegalPrefix() && !pre.isError())
throw new Type.Malformed(pre, sym.nameString()); throw new Type.Malformed(pre, sym.nameString());
rebind: rebind:
if (sym.isAbstractType()) { if (sym.isAbstractType()) {
@ -225,7 +225,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags {
return new ExtTypeRef(pre, sym, args); return new ExtTypeRef(pre, sym, args);
} }
private static boolean isLegalTypeRef(Type pre, Symbol sym, Type[] args) { private static boolean isLegalTypeRef(Type pre, Symbol sym, Type[] args) {
if (!pre.isLegalPrefix() && !pre.isError()) return false; if (sym.kind == TYPE && !pre.isLegalPrefix() && !pre.isError()) return false;
if (!sym.isType() && !sym.isError()) return false; if (!sym.isType() && !sym.isError()) return false;
// !!! return args.length == 0 || args.length == sym.typeParams().length; // !!! return args.length == 0 || args.length == sym.typeParams().length;
return true; return true;
@ -687,9 +687,12 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags {
return true; return true;
case TypeRef(_, Symbol sym, _): case TypeRef(_, Symbol sym, _):
if (sym.isParameter() && sym.isSynthetic()) return true; if (sym.isParameter() && sym.isSynthetic()) return true;
return false;
/*
return sym.kind == CLASS && return sym.kind == CLASS &&
((sym.flags & JAVA) != 0 || ((sym.flags & JAVA) != 0 ||
(sym.flags & (TRAIT | ABSTRACT)) == 0); (sym.flags & (TRAIT | ABSTRACT)) == 0);
*/
default: default:
return false; return false;
} }
@ -806,33 +809,34 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags {
return sym.info().lookupNonPrivate(name); return sym.info().lookupNonPrivate(name);
case CompoundType(Type[] parts, Scope members): case CompoundType(Type[] parts, Scope members):
Symbol sym = members.lookup(name); Symbol sym = members.lookup(name);
if (sym.kind != NONE && (sym.flags & PRIVATE) == 0) if (sym.kind != NONE && (sym.flags & PRIVATE) == 0) return sym;
return sym; else return lookupNonPrivate(parts, name);
// search base types in reverse; non-abstract members
// take precedence over abstract ones.
int i = parts.length;
sym = Symbol.NONE;
while (i > 0) {
i--;
Symbol sym1 = parts[i].lookupNonPrivate(name);
if (sym1.kind != NONE &&
(sym1.flags & PRIVATE) == 0 &&
(sym.kind == NONE
||
(sym.flags & DEFERRED) != 0 &&
(sym1.flags & DEFERRED) == 0
||
(sym.flags & DEFERRED) == (sym1.flags & DEFERRED) &&
sym1.owner().isSubClass(sym.owner())))
sym = sym1;
}
return sym;
default: default:
return Symbol.NONE; return Symbol.NONE;
} }
} }
public static Symbol lookupNonPrivate(Type[] parts, Name name) {
// search base types in reverse; non-abstract members
// take precedence over abstract ones.
int i = parts.length;
Symbol sym = Symbol.NONE;
while (i > 0) {
i--;
Symbol sym1 = parts[i].lookupNonPrivate(name);
if (sym1.kind != NONE &&
(sym.kind == NONE
||
(sym.flags & DEFERRED) != 0 &&
(sym1.flags & DEFERRED) == 0
||
(sym.flags & DEFERRED) == (sym1.flags & DEFERRED) &&
sym1.owner().isSubClass(sym.owner())))
sym = sym1;
}
return sym;
}
/** /**
* Looks up in the current type a symbol with the same name as the * Looks up in the current type a symbol with the same name as the
* given symbol and whose type (as seen from the given prefix) is * given symbol and whose type (as seen from the given prefix) is
@ -2342,6 +2346,55 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags {
} }
} }
/** Does this type match type `tp', so that corresponding symbols with
* the two types would be taken to override each other?
*/
public boolean overrides(Type tp) {
switch (this) {
case OverloadedType(Symbol[] alts, Type[] alttypes):
for (int i = 0; i < alttypes.length; i++) {
if (alttypes[i].overrides(tp)) return true;
}
return false;
default:
switch (tp) {
case MethodType(Symbol[] ps1, Type res1):
switch (this) {
case MethodType(Symbol[] ps, Type res):
if (ps.length != ps1.length) return false;
for (int i = 0; i < ps.length; i++) {
Symbol p1 = ps1[i];
Symbol p = ps[i];
if (!p1.type().isSameAs(p.type()) ||
(p1.flags & (DEF | REPEATED)) != (p.flags & (DEF | REPEATED)))
return false;
}
return res.overrides(res1);
}
return false;
case PolyType(Symbol[] ps1, Type res1):
switch (this) {
case PolyType(Symbol[] ps, Type res):
if (ps.length != ps1.length) return false;
for (int i = 0; i < ps.length; i++)
if (!ps1[i].info().subst(ps1, ps).isSameAs(ps[i].info()) ||
!ps[i].loBound().isSameAs(ps1[i].loBound().subst(ps1, ps)) ||
!ps[i].vuBound().isSameAs(ps1[i].vuBound().subst(ps1, ps)))
return false;
return res.overrides(res1.subst(ps1, ps));
}
return false;
case OverloadedType(_, _):
throw new ApplicationError("overrides inapplicable for " + tp);
default:
return true;
}
}
}
// Closures and Least Upper Bounds --------------------------------------------------- // Closures and Least Upper Bounds ---------------------------------------------------
/** The closure of this type, i.e. the widened type itself followed by all /** The closure of this type, i.e. the widened type itself followed by all

View File

@ -226,6 +226,7 @@ public class ClassfileParser implements ClassfileConstants {
symbol = owner.newTerm(Position.NOPOS, sflags, name); symbol = owner.newTerm(Position.NOPOS, sflags, name);
} }
setParamOwners(type, symbol); setParamOwners(type, symbol);
symbol.addInheritedOverloaded(type);
symbol.setInfo(type); symbol.setInfo(type);
attrib.readAttributes(symbol, type, METH_ATTR); attrib.readAttributes(symbol, type, METH_ATTR);
if (name != CONSTR_N) { if (name != CONSTR_N) {

View File

@ -138,7 +138,7 @@ public class Pickle implements Kinds, Modifiers, EntryTags {
putSymbol(it.next()); putSymbol(it.next());
break; break;
case VAL: case VAL:
putType(sym.info()); putType(sym.removeInheritedOverloaded(sym.info()));
if (sym.isConstructor() && if (sym.isConstructor() &&
sym == sym.constructorClass().allConstructors()) sym == sym.constructorClass().allConstructors())
putSymbol(sym.constructorClass()); putSymbol(sym.constructorClass());
@ -358,7 +358,7 @@ public class Pickle implements Kinds, Modifiers, EntryTags {
writeRef(sym.allConstructors()); writeRef(sym.allConstructors());
break; break;
case VAL: case VAL:
writeRef(sym.info()); writeRef(sym.removeInheritedOverloaded(sym.info()));
if (sym.isConstructor() && if (sym.isConstructor() &&
sym == sym.constructorClass().allConstructors()) sym == sym.constructorClass().allConstructors())
writeRef(sym.constructorClass()); writeRef(sym.constructorClass());

View File

@ -306,7 +306,9 @@ public class UnPickle implements Kinds, Modifiers, EntryTags, TypeTags {
Symbol clasz = readSymbolRef(); Symbol clasz = readSymbolRef();
assert clasz == sym.moduleClass(): Debug.show(sym); assert clasz == sym.moduleClass(): Debug.show(sym);
} }
sym.setInfo(getType(inforef, sym)); Type owntype = getType(inforef, sym);
sym.addInheritedOverloaded(owntype);
sym.setInfo(owntype);
break; break;
default: default:

View File

@ -222,15 +222,21 @@ public class AddInterfaces extends GenTransformer {
/** /**
* Returns the tree of the given class whose body is built by * Returns the tree of the given class whose body is built by
* adding to the given body the class members. Non-abstract * adding to the given body the class members. Non-abstract
* methods are removed from the given method map. All other * methods are removed from the ngiven method map. All other
* members are generated from their symbol. * members are generated from their symbol.
*/ */
private Tree getClassTree(Symbol clasz, TreeList body, Map methods) { private Tree getClassTree(Symbol clasz, TreeList body, Map methods) {
Scope members = clasz.nextInfo().members(); Scope members = clasz.nextInfo().members();
/*
for (Scope.SymbolIterator i = members.iterator(false); i.hasNext(); ) {
Symbol sym = i.next();
System.out.println(clasz + " defines " + sym + ":" + sym.getType());
}
*/
for (Scope.SymbolIterator i = members.iterator(true); i.hasNext(); ) { for (Scope.SymbolIterator i = members.iterator(true); i.hasNext(); ) {
Symbol member = i.next(); Symbol member = i.next();
if (!member.isTerm()) continue; if (!member.isTerm()) continue;
body.append(getMemberTree(member, methods)); body.append(getMemberTree(clasz, member, methods));
} }
return gen.ClassDef(clasz, body.toArray()); return gen.ClassDef(clasz, body.toArray());
} }
@ -240,11 +246,11 @@ public class AddInterfaces extends GenTransformer {
* removed from the given method map. All other members are * removed from the given method map. All other members are
* generated from their symbol. * generated from their symbol.
*/ */
private Tree getMemberTree(Symbol member, Map methods) { private Tree getMemberTree(Symbol clasz, Symbol member, Map methods) {
if (!member.isMethod()) return gen.ValDef(member, Tree.Empty); if (!member.isMethod()) return gen.ValDef(member, Tree.Empty);
if (member.isDeferred()) return gen.DefDef(member, Tree.Empty); if (member.isDeferred()) return gen.DefDef(member, Tree.Empty);
Tree method = (Tree)methods.remove(member); Tree method = (Tree)methods.remove(member);
assert method != null: Debug.show(member); assert method != null: Debug.show(clasz + "." + member + ":" + member.info() + member.locationString());
return method; return method;
} }

View File

@ -113,7 +113,14 @@ public class UnCurry extends OwnerTransformer
System.out.flush(); System.out.flush();
//uncurry type and symbol //uncurry type and symbol
Type prevtype = tree.type; Type prevtype = tree.type;
if (prevtype != null) tree.type = descr.uncurry(prevtype); if (prevtype != null) {
switch (prevtype) {
case OverloadedType(_, _):
assert tree.symbol() != null;
prevtype = tree.symbol().removeInheritedOverloaded(prevtype);
}
tree.type = descr.uncurry(prevtype);
}
switch (tree) { switch (tree) {
case ClassDef(_, _, AbsTypeDef[] tparams, ValDef[][] vparams, Tree tpe, Template impl): case ClassDef(_, _, AbsTypeDef[] tparams, ValDef[][] vparams, Tree tpe, Template impl):
return copy.ClassDef( return copy.ClassDef(

View File

@ -30,7 +30,7 @@ public class UnCurryPhase extends Phase implements Modifiers {
* - if symbol is a def parameter with transformed type T, return () => T * - if symbol is a def parameter with transformed type T, return () => T
*/ */
public Type transformInfo(Symbol sym, Type tp0) { public Type transformInfo(Symbol sym, Type tp0) {
Type tp1 = uncurry(tp0); Type tp1 = uncurry(sym.removeInheritedOverloaded(tp0));
if (sym.isDefParameter()) return global.definitions.FUNCTION_TYPE(Type.EMPTY_ARRAY, tp1); if (sym.isDefParameter()) return global.definitions.FUNCTION_TYPE(Type.EMPTY_ARRAY, tp1);
else return tp1; else return tp1;
} }

View File

@ -76,9 +76,12 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
void checkAllOverrides(int pos, Symbol clazz) { void checkAllOverrides(int pos, Symbol clazz) {
Type[] closure = clazz.closure(); Type[] closure = clazz.closure();
for (int i = 0; i < closure.length; i++) { for (int i = 0; i < closure.length; i++) {
for (Scope.SymbolIterator it = closure[i].members().iterator(true); Type basetype = closure[i];
Symbol baseclazz = basetype.symbol();
for (Scope.SymbolIterator it = basetype.members().iterator(true);
it.hasNext();) { it.hasNext();) {
checkOverride(pos, clazz, it.next()); Symbol sym = it.next();
if (sym.owner() == baseclazz) checkOverride(pos, clazz, sym);
} }
} }
@ -86,12 +89,12 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
for (Scope.SymbolIterator it = clazz.members().iterator(true); for (Scope.SymbolIterator it = clazz.members().iterator(true);
it.hasNext();) { it.hasNext();) {
Symbol sym = it.next(); Symbol sym = it.next();
if ((sym.flags & OVERRIDE) != 0) { if ((sym.flags & OVERRIDE) != 0 && sym.owner() == clazz) {
int i = parents.length - 1; int i = parents.length - 1;
while (i >= 0 && sym.overriddenSymbol(parents[i]).kind == NONE) while (i >= 0 && sym.overriddenSymbol(parents[i]).kind == NONE)
i--; i--;
if (i < 0) { if (i < 0) {
unit.error(sym.pos, sym + " overrides nothing"); unit.error(sym.pos, sym + ":" + sym.type() + sym.locationString() + " overrides nothing");//debug
sym.flags &= ~OVERRIDE; sym.flags &= ~OVERRIDE;
} else if (sym.isAbstractOverride() && } else if (sym.isAbstractOverride() &&
sym.overriddenSymbol(parents[0]).kind == NONE) { sym.overriddenSymbol(parents[0]).kind == NONE) {
@ -117,7 +120,8 @@ public class RefCheck extends Transformer implements Modifiers, Kinds {
switch (member1.info()) { switch (member1.info()) {
case OverloadedType(Symbol[] alts, _): case OverloadedType(Symbol[] alts, _):
for (int i = 0; i < alts.length; i++) { for (int i = 0; i < alts.length; i++) {
if (normalizedInfo(self, alts[i]).isSubType(template)) { if (normalizedInfo(self, alts[i]).isSubType(template) &&
alts[i].owner() == clazz) {
if (member == other) if (member == other)
member = alts[i]; member = alts[i];
else else

View File

@ -27,9 +27,8 @@ public class RefCheckPhase extends Phase {
} }
public Type transformInfo(Symbol sym, Type tp) { public Type transformInfo(Symbol sym, Type tp) {
if (sym.isModule() && !sym.isStatic()) { if (sym.isModule() && !sym.isStatic())
return Type.PolyType(Symbol.EMPTY_ARRAY, tp); return Type.PolyType(Symbol.EMPTY_ARRAY, tp);
}
else else
return tp; return tp;
} }

View File

@ -1,4 +1,4 @@
bug96.scala:5: method foo overrides nothing bug96.scala:5: method foo:(def scala.Any)java.lang.Object in class B overrides nothing
override def foo(def x: Any): Object = null; override def foo(def x: Any): Object = null;
^ ^
one error found one error found