diff options
author | Martin Odersky <odersky@gmail.com> | 2004-01-15 16:17:59 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2004-01-15 16:17:59 +0000 |
commit | 399482a6ba2e61f379703c05aeb47c6c39f0fdfa (patch) | |
tree | 54afc8ff65d5c1a56539ad3af5955034a1f9e6a9 | |
parent | 08ab698c371a7cf5e0621c3c2d9c882721d79aa8 (diff) | |
download | scala-399482a6ba2e61f379703c05aeb47c6c39f0fdfa.tar.gz scala-399482a6ba2e61f379703c05aeb47c6c39f0fdfa.tar.bz2 scala-399482a6ba2e61f379703c05aeb47c6c39f0fdfa.zip |
*** empty log message ***
-rw-r--r-- | doc/reference/ScalaReference.tex | 65 | ||||
-rw-r--r-- | sources/scala/tools/scalac/ast/parser/Parser.scala | 2 | ||||
-rw-r--r-- | sources/scala/tools/scalac/typechecker/Analyzer.scala | 15 | ||||
-rw-r--r-- | sources/scalac/symtab/Type.java | 62 | ||||
-rw-r--r-- | test/files/neg/bug44.check | 4 | ||||
-rw-r--r-- | test/files/neg/refine.check | 4 | ||||
-rw-r--r-- | test/files/neg/vincent1.check | 2 | ||||
-rw-r--r-- | test/files/pos/MailBox.scala | 2 | ||||
-rw-r--r-- | test/neg/bug44.check | 4 | ||||
-rw-r--r-- | test/neg/refine.check | 4 | ||||
-rw-r--r-- | test/neg/vincent1.check | 2 | ||||
-rw-r--r-- | test/pos/MailBox.scala | 2 |
12 files changed, 126 insertions, 42 deletions
diff --git a/doc/reference/ScalaReference.tex b/doc/reference/ScalaReference.tex index 5c106a3e58..586daf401c 100644 --- a/doc/reference/ScalaReference.tex +++ b/doc/reference/ScalaReference.tex @@ -304,7 +304,7 @@ referenced entity in $T$. Type ::= Type1 `=>' Type | `(' [Types] `)' `=>' Type | Type1 - Type1 ::= SimpleType {with SimpleType} + Type1 ::= SimpleType {with SimpleType} [Refinement] SimpleType ::= StableId | SimpleType `#' id | Path `.' type @@ -318,12 +318,14 @@ take type parameters and yield types. A subset of first-order types called {\em value types} represents sets of (first-class) values. Value types are either {\em concrete} or {\em abstract}. Every concrete value type can be represented as a {\em class type}, i.e.\ a -type designator (\sref{sec:type-desig}) that refers to a -class\footnote{We assume that objects and packages also implicitly -define a class (of the same name as the object or package, but -inaccessible to user programs).} (\sref{sec:classes}), or as a {\em -compound type} (\sref{sec:compound-types}) of class types. -\todo{verify whether operands need to be class types} +type designator (\sref{sec:type-desig}) that refers to a +class\footnote{We assume that objects and packages also +implicitly define a class (of the same name as the object or package, +but inaccessible to user programs).} (\sref{sec:classes}), +or as a {\em compound type} (\sref{sec:compound-types}) +consisting of class types and possibly +also a refinement (\sref{sec:refinements}) that further constrains the +types of its members. A shorthand exists for denoting function types (\sref{sec:function-types}). Abstract value types are introduced by @@ -472,14 +474,25 @@ the following types are ill-formed: \label{sec:compound-types} \syntax\begin{lstlisting} - Type ::= SimpleType {with SimpleType} + Type ::= SimpleType {with SimpleType} [Refinement] + Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' + RefineStat ::= Dcl + | type TypeDef {`,' TypeDef} + | \end{lstlisting} -A compound type ~\lstinline@$T_1$ with $\ldots$ with $T_n$ {$R\,$}@~ -represents objects with members as given in the component types $T_1 -\commadots T_n$. Each component type $T_i$ must be a class type and -the base class sequence generated by types $T_1 \commadots T_n$ must -be well-formed (\sref{sec:basetypes-wf}). +A compound type ~\lstinline@$T_1$ with $\ldots$ with $T_n$ {$R\,$}@~ represents +objects with members as given in the component types $T_1 \commadots +T_n$ and the refinement \lstinline@{$R\,$}@. Each component type $T_i$ must be a +class type and the base class sequence generated by types $T_1 +\commadots T_n$ must be well-formed (\sref{sec:basetypes-wf}). A +refinement \lstinline@{$R\,$}@ contains declarations and type +definitions. Each declaration or definition in a refinement must +override a declaration or definition in one of the component types +$T_1 \commadots T_n$. The usual rules for overriding (\sref{}) +apply. If no refinement is given, the empty refinement is implicitly +added, i.e. ~\lstinline@$T_1$ with $\ldots$ with $T_n$@~ is a shorthand for +~\lstinline@$T_1$ with $\ldots$ with $T_n$ {}@. \subsection{Function Types} \label{sec:function-types} @@ -745,7 +758,10 @@ consisting only of package or object selectors and ending in $O$, then ~\lstinline@$O$.this.type $\equiv p$.type@. \item Two compound types are equivalent if their component types are -pairwise equivalent. +pairwise equivalent and their refinements are equivalent. Two +refinements are equivalent if they bind the same names and the +modifiers, types and bounds of every declared entity are equivalent in +both refinements. \item Two method types are equivalent if they have equivalent result types, both have the same number of parameters, and corresponding @@ -922,8 +938,9 @@ the expression is typed and evaluated is if it was \end{lstlisting} A {\em declaration} introduces names and assigns them types. It can -only appear as one of the statements of a class definition -(\sref{sec:templates}). +appear as one of the statements of a class definition +(\sref{sec:templates}) or as part of a refinement in a compound +type (\sref{sec:refinements}). A {\em definition} introduces names that denote terms or types. It can form part of an object or class definition or it can be local to a @@ -2703,7 +2720,13 @@ 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$@. +\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. @@ -3375,7 +3398,7 @@ Concretely, we distinguish the following kinds of patterns. A {\em wild-card pattern} \_ matches any value. A {\em typed pattern} $\_: T$ matches values of type $T$. The type $T$ may be - a class type or a compound type. + a class type or a compound type; it may not contain a refinement (\sref{sec:refinements}). This pattern matches any non-null value of type $T$. $T$ must conform to the pattern's expected type. A pattern $x:T$ is treated the same way as $x @ (_:T)$ @@ -4238,7 +4261,7 @@ grammar. Type ::= Type1 `=>' Type | `(' [Types] `)' `=>' Type | Type1 - Type1 ::= SimpleType {with SimpleType} + Type1 ::= SimpleType {with SimpleType} [Refinement] SimpleType ::= SimpleType TypeArgs | SimpleType `#' id | StableId @@ -4246,6 +4269,10 @@ grammar. | `(' Type ')' TypeArgs ::= `[' Types `]' Types ::= Type {`,' Type} + Refinement ::= `{' [RefineStat {`;' RefineStat}] `}' + RefineStat ::= Dcl + | type TypeDef {`,' TypeDef} + | Exprs ::= Expr {`,' Expr} Expr ::= Bindings `=>' Expr diff --git a/sources/scala/tools/scalac/ast/parser/Parser.scala b/sources/scala/tools/scalac/ast/parser/Parser.scala index 830c507e44..6cd6effa88 100644 --- a/sources/scala/tools/scalac/ast/parser/Parser.scala +++ b/sources/scala/tools/scalac/ast/parser/Parser.scala @@ -690,7 +690,7 @@ class Parser(unit: Unit) { s.nextToken(); ts.append(simpleType()); } - val rs = /*if (s.token == LBRACE) refinement() else*/ Tree.EMPTY_ARRAY; + val rs = if (s.token == LBRACE) refinement() else Tree.EMPTY_ARRAY; make.CompoundType(pos, ts.toArray(), rs) } else { t diff --git a/sources/scala/tools/scalac/typechecker/Analyzer.scala b/sources/scala/tools/scalac/typechecker/Analyzer.scala index 5fd7997e9d..76355d1a6e 100644 --- a/sources/scala/tools/scalac/typechecker/Analyzer.scala +++ b/sources/scala/tools/scalac/typechecker/Analyzer.scala @@ -2283,7 +2283,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( val parentTypes = clazz.info().parents(); val refinement: Scope = new Scope(); val base: Type = Type.compoundTypeWithOwner(context.enclClass.owner, parentTypes, Scope.EMPTY); - /* val it: Scope$SymbolIterator = clazz.members().iterator(); while (it.hasNext()) { val sym1: Symbol = it.next(); @@ -2293,7 +2292,6 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( .isSameAs(sym1.getType())) refinement.enter(sym1); } - */ val owntype = if (refinement.isEmpty() && parentTypes.length == 1) parentTypes(0) @@ -2764,16 +2762,23 @@ class Analyzer(global: scalac_Global, descr: AnalyzerPhase) extends Transformer( case Tree$CompoundType(parents, refinements) => val parents1 = transform(parents, TYPEmode); - val ptypes = Tree.typeOf(parents); + val ptypes = new Array[Type](parents1.length); + { var i = 0; while (i < parents1.length) { + val tp = parents(i).getType(); + if (i > 0 || tp.unalias().symbol().kind != TYPE) + checkClassType(parents(i).pos, tp); + ptypes(i) = tp; + i = i + 1 + }} val members: Scope = new Scope(); val self: Type = Type.compoundTypeWithOwner(context.enclClass.owner, ptypes, members); val clazz: Symbol = self.symbol(); pushContext(tree, clazz, members); - var i = 0; while (i < refinements.length) { + { var i = 0; while (i < refinements.length) { val m = enterSym(refinements(i)); m.flags = m.flags | OVERRIDE; i = i + 1 - } + }} val refinements1 = transformStatSeq(refinements, Symbol.NONE); popContext(); copy.CompoundType(tree, parents1, refinements1) diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index b8b03a9ffb..e9665e13d8 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -1658,6 +1658,11 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { case ThisType(Symbol sym): if (sym == from) return to; else return t; + case TypeRef(Type pre, Symbol sym, Type[] args): + Type pre1 = apply(pre); + Type[] args1 = map(args); + if (pre1 == pre && args1 == args) return t; + else return typeRef(pre1, pre1.rebind(sym), args1); default: return map(t); } @@ -2579,9 +2584,36 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } } + static int recCount = 0; + static boolean giveUp = false; + static int recLimit = 10; + + public static Type lub(Type[] tps) { + if (recCount == recLimit) { + giveUp = true; + return Global.instance.definitions.ANY_TYPE(); + } else { + recCount++; + Type result = lub0(tps); + recCount--; + if (recCount == 0) { + if (giveUp) { + giveUp = false; + throw new Error("failure to compute least upper bound of types " + + ArrayApply.toString(tps, "", " and ", ";\n") + + "an approximation is: " + result + ";\n" + + "additional type annotations are needed"); + } else { + giveUp = false; + } + } + return result; + } + } + /** Return the least upper bound of non-empty array of types `tps'. */ - public static Type lub(Type[] tps) { + public static Type lub0(Type[] tps) { //System.out.println("lub" + ArrayApply.toString(tps));//DEBUG if (tps.length == 0) return Global.instance.definitions.ALL_TYPE(); @@ -2754,6 +2786,29 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { } public static Type glb(Type[] tps) { + if (recCount == recLimit) { + giveUp = true; + return Global.instance.definitions.ALL_TYPE(); + } else { + recCount++; + Type result = glb0(tps); + recCount--; + if (recCount == 0) { + if (giveUp) { + giveUp = false; + throw new Error("failure to compute greatest lower bound of types " + + ArrayApply.toString(tps, "", " and ", ";\n") + + "an approximation is: " + result + ";\n" + + "additional type annotations are needed"); + } else { + giveUp = false; + } + } + return result; + } + } + + public static Type glb0(Type[] tps) { if (tps.length == 0) return Global.instance.definitions.ANY_TYPE(); // step one: eliminate redunandant types; return if one one is left @@ -2769,10 +2824,8 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { treftl = new Type.List(tps[i], treftl); break; case CompoundType(Type[] parents, Scope members): - /* if (!members.isEmpty()) comptl = new Type.List(tps[i], comptl); - */ for (int j = 0; j < parents.length; j++) treftl = new Type.List(parents[j], treftl); break; @@ -2787,7 +2840,7 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { Type glbThisType = glbType.narrow(); // step 3: compute glb of all refinements. - /* + Scope members = Scope.EMPTY; if (comptl != List.EMPTY) { Type[] comptypes = comptl.toArrayReverse(); Scope[] refinements = new Scope[comptypes.length]; @@ -2801,7 +2854,6 @@ public class Type implements Modifiers, Kinds, TypeTags, EntryTags { Global.instance.definitions.ALLREF_TYPE(), treftl); } } - */ // eliminate redudant typerefs Type[] treftypes = elimRedundant(treftl.toArrayReverse(), false); diff --git a/test/files/neg/bug44.check b/test/files/neg/bug44.check index 9347758ac9..d40af82749 100644 --- a/test/files/neg/bug44.check +++ b/test/files/neg/bug44.check @@ -1,6 +1,6 @@ bug44.scala:2: type mismatch; - found : scala.Object - required: scala.Object { def t: scala.Int } + found : java.lang.Object + required: java.lang.Object { def t: scala.Int } var x: Object { def t: Int; } = new Object() { ^ one error found diff --git a/test/files/neg/refine.check b/test/files/neg/refine.check index 271451e65e..18f4fad76a 100644 --- a/test/files/neg/refine.check +++ b/test/files/neg/refine.check @@ -1,6 +1,6 @@ refine.scala:3: type mismatch; - found : scala.Object - required: scala.Object { def t(): java.lang.String } + found : java.lang.Object + required: java.lang.Object { def t(): java.lang.String } val x: Object { def t(): String } = new Object { ^ one error found diff --git a/test/files/neg/vincent1.check b/test/files/neg/vincent1.check index a9f60e9ad2..aa65a52341 100644 --- a/test/files/neg/vincent1.check +++ b/test/files/neg/vincent1.check @@ -1,4 +1,4 @@ -vincent1.scala:7: type x.type escapes its defining scope as part of scala.Object { type T = x.T } +vincent1.scala:7: type x.type escapes its defining scope as part of java.lang.Object with scala.ScalaObject { type T = x.T } class Functor(x: A) { type T = x.T } ^ vincent1.scala:9: type x.type escapes its defining scope as part of test.B { type T = x.T } diff --git a/test/files/pos/MailBox.scala b/test/files/pos/MailBox.scala index 9094b73399..3a633e3fbe 100644 --- a/test/files/pos/MailBox.scala +++ b/test/files/pos/MailBox.scala @@ -2,7 +2,7 @@ package test; import scala.concurrent._; -class MailBox with Monitor { +class MailBox { private class LinkedList[a] { var elem: a = _; var next: LinkedList[a] = null; diff --git a/test/neg/bug44.check b/test/neg/bug44.check index 9347758ac9..d40af82749 100644 --- a/test/neg/bug44.check +++ b/test/neg/bug44.check @@ -1,6 +1,6 @@ bug44.scala:2: type mismatch; - found : scala.Object - required: scala.Object { def t: scala.Int } + found : java.lang.Object + required: java.lang.Object { def t: scala.Int } var x: Object { def t: Int; } = new Object() { ^ one error found diff --git a/test/neg/refine.check b/test/neg/refine.check index 271451e65e..18f4fad76a 100644 --- a/test/neg/refine.check +++ b/test/neg/refine.check @@ -1,6 +1,6 @@ refine.scala:3: type mismatch; - found : scala.Object - required: scala.Object { def t(): java.lang.String } + found : java.lang.Object + required: java.lang.Object { def t(): java.lang.String } val x: Object { def t(): String } = new Object { ^ one error found diff --git a/test/neg/vincent1.check b/test/neg/vincent1.check index a9f60e9ad2..aa65a52341 100644 --- a/test/neg/vincent1.check +++ b/test/neg/vincent1.check @@ -1,4 +1,4 @@ -vincent1.scala:7: type x.type escapes its defining scope as part of scala.Object { type T = x.T } +vincent1.scala:7: type x.type escapes its defining scope as part of java.lang.Object with scala.ScalaObject { type T = x.T } class Functor(x: A) { type T = x.T } ^ vincent1.scala:9: type x.type escapes its defining scope as part of test.B { type T = x.T } diff --git a/test/pos/MailBox.scala b/test/pos/MailBox.scala index 9094b73399..3a633e3fbe 100644 --- a/test/pos/MailBox.scala +++ b/test/pos/MailBox.scala @@ -2,7 +2,7 @@ package test; import scala.concurrent._; -class MailBox with Monitor { +class MailBox { private class LinkedList[a] { var elem: a = _; var next: LinkedList[a] = null; |