diff options
author | Martin Odersky <odersky@gmail.com> | 2003-09-10 13:50:32 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-09-10 13:50:32 +0000 |
commit | 957c42dadf55e3b67511077acfc4dd05e9a76b1d (patch) | |
tree | 2d2e3e6f8b0c903963d5b3a228bcaa0172dc4041 | |
parent | 86451906a534a8a09eafde0f35591071f0f0d5a3 (diff) | |
download | scala-957c42dadf55e3b67511077acfc4dd05e9a76b1d.tar.gz scala-957c42dadf55e3b67511077acfc4dd05e9a76b1d.tar.bz2 scala-957c42dadf55e3b67511077acfc4dd05e9a76b1d.zip |
*** empty log message ***
-rw-r--r-- | doc/reference/ScalaReference.tex | 55 | ||||
-rw-r--r-- | sources/meta/scalac/checkers/MetaCheckTreeNodes.java | 4 | ||||
-rw-r--r-- | sources/scalac/symtab/Type.java | 48 | ||||
-rw-r--r-- | sources/scalac/typechecker/Analyzer.java | 25 | ||||
-rw-r--r-- | sources/scalac/typechecker/RefCheck.java | 123 |
5 files changed, 125 insertions, 130 deletions
diff --git a/doc/reference/ScalaReference.tex b/doc/reference/ScalaReference.tex index 5d44c69411..1167828aad 100644 --- a/doc/reference/ScalaReference.tex +++ b/doc/reference/ScalaReference.tex @@ -546,6 +546,7 @@ empty : [a >: All <: Any] List[a] union : [a >: All <: Comparable[a]] (x: Set[a], xs: Set[a]) Set[a] . \end{lstlisting} +\comment{ \subsection{Overloaded Types} \label{sec:overloaded-types} \newcommand{\overload}{\la\mbox{\sf and}\ra} @@ -581,6 +582,7 @@ def f(x: T): T = $\ldots$; val f = 0 \end{lstlisting} define a function \code{f} which has type ~\lstinline@(x: T)T $\overload$ Int@. +} \section{Base Classes and Member Definitions} \label{sec:base-classes} @@ -1351,14 +1353,12 @@ determined from the type of the function body. An overloaded definition is a set of $n > 1$ value or function definitions in the same statement sequence that define the same name, -binding it to types ~\lstinline@$T_1 \commadots T_n$@, respectively. The -individual definitions are called {\em alternatives}. Alternatives -always need to specify the type of the defined entity completely. All -alternatives must have the same modifiers. It is an error if the types -of two alternatives $T_i$ and $T_j$ have the same -erasure (\sref{sec:erasure}). An overloaded definition defines a -single entity, of type $T_1 \overload \ldots \overload T_n$ -(\sref{sec:overloaded-types}). +binding it to types ~\lstinline@$T_1 \commadots T_n$@, respectively. +The individual definitions are called {\em alternatives}. Overloaded +definitions may only appear in the statement sequence of a template. +Alternatives always need to specify the type of the defined entity +completely. It is an error if the types of two alternatives $T_i$ and +$T_j$ have the same erasure (\sref{sec:erasure}). \todo{Say something about bridge methods.} %This must be a well-formed @@ -2100,7 +2100,7 @@ trait Ord[t <: Ord[t]]: t { \end{lstlisting} An object definition defines a single object of a new class. Its -most general is +most general form is ~\lstinline@object $m$: $s$ extends $t$@. Here, \begin{itemize} \item[] @@ -2603,15 +2603,15 @@ new $sc$ with $mc_1$ with $\ldots$ with $mc_n$ {$stats\,$} \end{lstlisting} where $n \geq 0$, $sc$ as well as $mc_1 \commadots mc_n$ are constructor invocations (of types $S, T_1 \commadots T_n$, say) and -$stats$ is a statement sequence containing initializer statements -and member definitions (\sref{sec:members}). The type of such an -instance creation expression is then the compound type -\lstinline@$S$ with $T_1$ with $\ldots$ with $T_n$ {$R\,$}@, where \lstinline@{$R\,$}@ is a -refinement (\sref{sec:compound-types}) which declares exactly those -members of $stats$ that override a member of $S$ or -$T_1 \commadots T_n$. For this type to be well-formed, $R$ -may not reference types defined in $stats$ which do not -themselves form part of $R$. +$stats$ is a statement sequence containing initializer statements and +member definitions (\sref{sec:members}). The type of such an instance +creation expression is then the compound type \lstinline@$S$ with +$T_1$ with $\ldots$ with $T_n$ {$R\,$}@, where \lstinline@{$R\,$}@ is +a refinement (\sref{sec:compound-types}) which declares exactly those +members of $stats$ that override a member of $S$ or $T_1 \commadots +T_n$. \todo{what about methods and overloaded defs?} For this type to +be well-formed, $R$ may not reference types defined in $stats$ which +do not themselves form part of $R$. The instance creation expression is evaluated by creating a fresh object, which is initialized by evaluating the expression template. @@ -3161,16 +3161,15 @@ by expression $e$. The scope of each formal parameter $x_i$ is $e$. If the expected type of the anonymous function is of the form -~\lstinline@scala.Function$n$[$S_1 \commadots S_n$, $R\,$]@, the expected type -of $e$ is $R$ and the type $T_i$ of any of the -parameters $x_i$ can be omitted, in which case -~\lstinline@$T_i$ = $S_i$@~ is assumed. If the expected type of the anonymous -function is some other type, all formal parameter types must be -explicitly given, and the expected type of $e$ is missing. The -type of the anonymous function is -~\lstinline@scala.Function$n$[$S_1 \commadots S_n$, $T\,$]@, where $T$ is -the type of $e$. $T$ must be equivalent to a type which does -not refer to any of the formal parameters $x_i$. +~\lstinline@scala.Function$n$[$S_1 \commadots S_n$, $R\,$]@, the +expected type of $e$ is $R$ and the type $T_i$ of any of the +parameters $x_i$ can be omitted, in which case ~\lstinline@$T_i$ = +$S_i$@~ is assumed. If the expected type of the anonymous function is +some other type, all formal parameter types must be explicitly given, +and the expected type of $e$ is missing. The type of the anonymous +function is ~\lstinline@scala.Function$n$[$S_1 \commadots S_n$, +$T\,$]@, where $T$ is the type of $e$. $T$ must be equivalent to a +type which does not refer to any of the formal parameters $x_i$. The anonymous function is evaluated as the instance creation expression \begin{lstlisting} diff --git a/sources/meta/scalac/checkers/MetaCheckTreeNodes.java b/sources/meta/scalac/checkers/MetaCheckTreeNodes.java index d18d012d20..11ad75d77a 100644 --- a/sources/meta/scalac/checkers/MetaCheckTreeNodes.java +++ b/sources/meta/scalac/checkers/MetaCheckTreeNodes.java @@ -78,8 +78,8 @@ public class MetaCheckTreeNodes extends AbstractTreeCaseExpander { case TreeType.Name(TreeKind kind): if (kind != TreeKind.Any && kind != TreeKind.Test) { - writer.println("assert " + (kind == TreeKind.Type ? "" : "!")+ - name +".isTypeName() :").indent(); + writer.println("assert " + name + ".is" + kind + "Name() :") + .indent(); printWrongKind(node, name, kind); writer.println(";").undent(); } diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index e3526f8830..03bee60328 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -1727,36 +1727,23 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { return result; } - public boolean specializes0(Symbol sym1) { - Symbol sym = lookup(sym1.name); - switch (sym.info()) { - case NoType: - return false; - case OverloadedType(Symbol[] alts, Type[] alttypes): - for (int i = 0; i < alts.length; i++) { - if (specializes0(alts[i], sym1)) return true; - } - return false; - default: - return specializes0(sym, sym1); - } - } - - private boolean specializes0(Symbol sym, Symbol sym1) { + private boolean specializes0(Symbol sym1) { Type self = narrow(); Symbol[] tparams = symbol().typeParams(); Type[] targs = typeArgs(); + Symbol sym = lookup(sym1.name); return - sym == sym1 - || - (sym.kind == sym1.kind || sym1.kind == TYPE) && - self.memberInfo(sym).subst(tparams, targs) - .isSubType(sym1.info().substThis(sym1.owner(), self)) && - sym1.loBound().substThis(sym1.owner(), self) - .isSubType(self.memberLoBound(sym).subst(tparams, targs)) - || - (sym.kind == TYPE && sym1.kind == ALIAS && - sym1.info().unalias().isSameAs(sym.type())); + sym.kind != NONE && + (sym == sym1 + || + (sym.kind == sym1.kind || sym1.kind == TYPE) && + self.memberInfo(sym).subst(tparams, targs) + .isSubType(sym1.info().substThis(sym1.owner(), self)) && + sym1.loBound().substThis(sym1.owner(), self) + .isSubType(self.memberLoBound(sym).subst(tparams, targs)) + || + (sym.kind == TYPE && sym1.kind == ALIAS && + sym1.info().unalias().isSameAs(sym.type()))); } /** Is this type the same as that type? @@ -2163,7 +2150,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { if (tps[i] == ErrorType) { return new Type[]{ErrorType}; } else { - assert tps[i].isObjectType() : tps[i]; + assert tps[i].isObjectType(): tps[i]; for (int j = 0; j < i && !redundant[i]; j++) { if (!redundant[j]) { if (tps[i].isSubType(tps[j])) { @@ -2197,6 +2184,9 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { if (tps.length == 0) return Global.instance.definitions.ALL_TYPE; + //If all types are method types with same parameters, + //compute lub of their result types. + // remove types that are subtypes of some other type. tps = elimRedundant(tps, true); if (tps.length == 1) return tps[0]; @@ -2231,8 +2221,6 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { while (j < tps.length) { rsyms[j] = tps[j].lookupNonPrivate(name); if (rsyms[j] == sym) break; - if (rsyms[j].isMethod()) break; // since methods cannot - // appear in refinements. rtps[j] = memberTp(tps[j], rsyms[j]) .substThis(tps[j].symbol(), lubThisType); rlbs[j] = tps[j].memberLoBound(rsyms[j]) @@ -2311,7 +2299,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { if (!members.isEmpty()) comptl = new Type.List(tps[i], comptl); for (int j = 0; j < parents.length; j++) - treftl = new Type.List(parents[i], treftl); + treftl = new Type.List(parents[j], treftl); break; case ThisType(_): case SingleType(_, _): diff --git a/sources/scalac/typechecker/Analyzer.java b/sources/scalac/typechecker/Analyzer.java index fc53218f5e..99629712a9 100644 --- a/sources/scalac/typechecker/Analyzer.java +++ b/sources/scalac/typechecker/Analyzer.java @@ -1117,7 +1117,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } catch (Type.Error ex) { reportTypeError(tree.pos, ex); tree.type = Type.ErrorType; - if (tree.hasSymbol() && tree.symbol() == null) tree.setSymbol(Symbol.ERROR); + if (tree.hasSymbol()) { + if (tree.symbol() != null) tree.symbol().setInfo(Type.ErrorType); + else tree.setSymbol(Symbol.ERROR); + } } this.unit = savedUnit; @@ -1235,7 +1238,8 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { if (clazz.isCaseClass()) { // set type to instantiated case class constructor - tree.type = clazz.primaryConstructor().type(); + tree.type = tree.type.prefix().memberType( + clazz.primaryConstructor()); switch (tree.type) { case PolyType(Symbol[] tparams, Type restp): try { @@ -2031,7 +2035,7 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { return error(tree.pos, "method with return needs result type"); } else { Symbol enclFun = context.owner.enclMethod(); - if (enclFun.kind == VAL) { + if (enclFun.kind == VAL && !enclFun.isConstructor()) { Tree expr1 = transform( expr, EXPRmode, enclFun.type().resultType()); return copy.Return(tree, expr1) @@ -2178,7 +2182,12 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { assert tsym.isType() : tsym; switch (fn1.type.unalias()) { case TypeRef(Type pre, Symbol c, Type[] argtypes): - if (c.kind == CLASS) { + if (c.kind != CLASS) { + error(tree.pos, + tsym + " is not a class; cannot be instantiated"); + } else if (!pre.isStable()) { + error(tree.pos, pre + " is not a legal prefix for a constructor"); + } else { c.initialize(); Symbol constr = c.allConstructors(); Tree fn0 = fn1; @@ -2206,9 +2215,6 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } //System.out.println(TreeInfo.methSymbol(fn1) + ":" + tp + " --> " + fn1.type + " of " + fn1);//DEBUG selfcc = TreeInfo.isSelfConstrCall(fn0); - } else { - error(tree.pos, - tsym + " is not a class; cannot be instantiated"); } break; default: @@ -2475,7 +2481,10 @@ public class Analyzer extends Transformer implements Modifiers, Kinds { } catch (Type.Error ex) { reportTypeError(tree.pos, ex); tree.type = Type.ErrorType; - if (tree.hasSymbol() && tree.symbol() == null) tree.setSymbol(Symbol.ERROR); + if (tree.hasSymbol()) { + if (tree.symbol() != null) tree.symbol().setInfo(Type.ErrorType); + else tree.setSymbol(Symbol.ERROR); + } return tree; } } diff --git a/sources/scalac/typechecker/RefCheck.java b/sources/scalac/typechecker/RefCheck.java index d3a603642a..b2e394458a 100644 --- a/sources/scalac/typechecker/RefCheck.java +++ b/sources/scalac/typechecker/RefCheck.java @@ -58,54 +58,76 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { // Override checking ------------------------------------------------------------ /** 1. Check all members of class `clazz' for overriding conditions. - * 2. Check that only abstract classes have deferred members + * 2. Check that only abstract classes have deferred members* * 3. Check that every member with an `override' modifier * overrides a concrete member. */ void checkAllOverrides(int pos, Symbol clazz) { Type[] closure = clazz.closure(); - HashMap/*<Symbol,Symbol>*/ overrides = null; + HashMap/*<Symbol,Symbol>*/ overrides = new HashMap(); for (int i = 0; i < closure.length; i++) { for (Scope.SymbolIterator it = closure[i].members().iterator(true); it.hasNext();) { - Symbol other = it.next(); - Symbol member = ((other.flags & PRIVATE) != 0) ? other - : clazz.info().lookup(other.name); - if (member.owner() == other.owner()) - member = other; - else if (member.type() instanceof Type.OverloadedType) - member = findOverriding(pos, clazz, member, other); - if (member.kind != NONE && member != other) - checkOverride(pos, clazz, member, other); - if (clazz.kind == CLASS && (clazz.flags & ABSTRACTCLASS) == 0) { - if ((member.flags & DEFERRED) != 0) { - abstractClassError( - clazz, - member + member.locationString() + " is not defined" + - (((member.flags & MUTABLE) == 0) ? "" - : "\n(Note that variables need to be initialized to be defined)")); - } else if ((member.flags & OVERRIDE) != 0) { - if (overrides == null) - overrides = new HashMap(); - if ((other.flags & DEFERRED) == 0 || - overrides.get(member) == null) - overrides.put(member, other); - } - } + checkOverride(pos, clazz, it.next(), overrides); } } - if (overrides != null) { - for (Iterator/*<Symbol>*/ it = overrides.keySet().iterator(); - it.hasNext();) { - Symbol member = (Symbol) it.next(); - Symbol other = (Symbol) overrides.get(member); - if ((other.flags & DEFERRED) != 0) { - abstractClassError( - clazz, member + member.locationString() + - " is marked `override' and overrides only abstract members" + other + other.locationString()); + for (Iterator/*<Symbol>*/ it = overrides.keySet().iterator(); + it.hasNext();) { + Symbol member = (Symbol) it.next(); + Symbol other = (Symbol) overrides.get(member); + if ((other.flags & DEFERRED) != 0) { + abstractClassError( + clazz, member + member.locationString() + + " is marked `override' and overrides only abstract members" + other + other.locationString()); + } + } + } + + void checkOverride(int pos, Symbol clazz, Symbol other, + HashMap/*<Symbol,Symbol>*/ overrides) { + Symbol member = other; + if ((other.flags & PRIVATE) == 0) { + Symbol member1 = clazz.info().lookup(other.name); + if (member1.kind != NONE && member1.owner() != other.owner()) { + switch (member1.info()) { + case OverloadedType(Symbol[] alts, _): + Type self = clazz.thisType(); + Type otherinfo = normalizedInfo(self, other); + for (int i = 0; i < alts.length; i++) { + if (normalizedInfo(self, alts[i]).isSubType(otherinfo)) { + if (member == other) + member = alts[i]; + else + unit.error( + pos, + "ambiguous override: both " + + member + ":" + normalizedInfo(self, member) + + "\n and " + alts[i] + ":" + normalizedInfo(self, alts[i]) + + "\n override " + other + ":" + otherinfo + + other.locationString()); + } + } + break; + default: + member = member1; } } } + if (member != other) { + checkOverride(pos, clazz, member, other); + } + if (clazz.kind == CLASS && (clazz.flags & ABSTRACTCLASS) == 0) { + if ((member.flags & DEFERRED) != 0) { + abstractClassError( + clazz, + member + member.locationString() + " is not defined" + + (((member.flags & MUTABLE) == 0) ? "" + : "\n(Note that variables need to be initialized to be defined)")); + } else if ((member.flags & OVERRIDE) != 0 && + ((other.flags & DEFERRED) == 0 || + overrides.get(member) == null)) + overrides.put(member, other); + } } //where private void abstractClassError(Symbol clazz, String msg) { @@ -116,32 +138,6 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { clazz.flags |= ABSTRACTCLASS; } - Symbol findOverriding(int pos, Symbol clazz, Symbol members, Symbol other) { - Type self = clazz.thisType(); - Symbol member = members; - Type memberinfo = normalizedInfo(self, member); - Type otherinfo = normalizedInfo(self, other); - switch (memberinfo) { - case OverloadedType(Symbol[] alts, Type[] alttypes): - for (int i = 0; i < alts.length; i++) { - if (alttypes[i].isSubType(otherinfo)) { - if (member == members) { - member = alts[i]; - memberinfo = alttypes[i]; - } else { - unit.error( - pos, - "ambiguous override: both " + - member + ":" + memberinfo + - "\n and " + alts[i] + ":" + alttypes[i] + - "\n override " + other + ":" + otherinfo + - other.locationString()); - } - } - } - } - return member; - } /** Check that all conditions for overriding `other' by `member' are met. * That is for overriding member M and overridden member O: @@ -232,7 +228,10 @@ public class RefCheck extends Transformer implements Modifiers, Kinds { Type normalizedInfo(Type site, Symbol sym) { Type tp = site.memberInfo(sym); - if (sym.kind == VAL && (sym.flags & STABLE) != 0) tp = tp.resultType(); + switch (tp) { + case PolyType(Symbol[] tparams, Type restp): + if (tparams.length == 0) return restp; + } return tp; } |