diff options
author | Martin Odersky <odersky@gmail.com> | 2003-05-19 11:12:09 +0000 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2003-05-19 11:12:09 +0000 |
commit | f7f15007686e355a2d8668bf890603be90810e29 (patch) | |
tree | bdb8a9a813fd1a8b32bc20b6988eafe16de4a2f8 /sources/scalac/symtab/Type.java | |
parent | 2300aac76adab6945ca2d2e3cb15320621a76150 (diff) | |
download | scala-f7f15007686e355a2d8668bf890603be90810e29.tar.gz scala-f7f15007686e355a2d8668bf890603be90810e29.tar.bz2 scala-f7f15007686e355a2d8668bf890603be90810e29.zip |
*** empty log message ***
Diffstat (limited to 'sources/scalac/symtab/Type.java')
-rw-r--r-- | sources/scalac/symtab/Type.java | 146 |
1 files changed, 141 insertions, 5 deletions
diff --git a/sources/scalac/symtab/Type.java b/sources/scalac/symtab/Type.java index 110a0f80bc..15c3d47649 100644 --- a/sources/scalac/symtab/Type.java +++ b/sources/scalac/symtab/Type.java @@ -141,6 +141,7 @@ public class Type implements Modifiers, Kinds, TypeTags { public Type widen() { return type().widen(); } + /** If this type is a singleton type whose type is another, the end of the chain, * otherwise the type itself. */ @@ -235,6 +236,25 @@ public class Type implements Modifiers, Kinds, TypeTags { return this; } + /** The lower approximation of this type (which must be a typeref) + */ + public Type loBound() { + switch (unalias()) { + case TypeRef(Type pre, Symbol sym, Type[] args): + Type lb = Global.instance.definitions.ANY_TYPE; + if (sym.kind == TYPE) { + lb = sym.loBound().asSeenFrom(pre, sym.owner()); + } + if (lb.isSameAs(Global.instance.definitions.ANY_TYPE) && + this.isSubType(Global.instance.definitions.ANYREF_TYPE)) { + lb = Global.instance.definitions.ANYREF_TYPE; + } + return lb; + default: + throw new ApplicationError(); + } + } + /** The thistype or singleton type corresponding to values of this type. */ public Type narrow() { @@ -1306,9 +1326,7 @@ public class Type implements Modifiers, Kinds, TypeTags { case TypeRef(_, Symbol sym, _): switch (that) { case TypeRef(Type pre1, Symbol sym1, _): - if (sym1.kind == TYPE && - this.isSubType( - sym1.loBound().asSeenFrom(pre1, sym1.owner()))) + if (sym1.kind == TYPE && this.isSubType(that.loBound())) return true; } if (sym.kind == ALIAS) @@ -1826,7 +1844,6 @@ public class Type implements Modifiers, Kinds, TypeTags { } /** Return the least upper bound of non-empty array of types `tps'. - * todo: treat types with refinements */ public static Type lub(Type[] tps) { //System.out.println("lub" + ArrayApply.toString(tps));//DEBUG @@ -1922,11 +1939,130 @@ public class Type implements Modifiers, Kinds, TypeTags { } private static Type glb(Type[] tps) { + // step one: eliminate redunandant types; return if one one is left tps = elimRedundant(tps, false); if (tps.length == 1) return tps[0]; - else return NoType; + + // step two: build arrays of all typerefs and all refinements + Type.List treftl = Type.List.EMPTY; + Type.List comptl = Type.List.EMPTY; + for (int i = 0; i < tps.length; i++) { + switch (tps[i]) { + case TypeRef(_, _, _): + treftl = new Type.List(tps[i], treftl); + break; + case CompoundType(Type[] parents, Scope members): + if (members.elems != Scope.Entry.NONE) + comptl = new Type.List(tps[i], comptl); + for (int j = 0; j < parents.length; j++) + treftl = new Type.List(parents[i], treftl); + break; + case ThisType(_): + case SingleType(_, _): + return Global.instance.definitions.ALL_TYPE; + } + } + + CompoundType glbType = compoundType(Type.EMPTY_ARRAY, new Scope()); + 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]; + for (int i = 0; i < comptypes.length; i++) + refinements[i] = comptypes[i].members(); + if (!setGlb(glbType.members, refinements, glbThisType)) { + // refinements don't have lower bound, so approximate + // by AllRef + glbType.members = Scope.EMPTY; + treftl = new Type.List( + Global.instance.definitions.ALLREF_TYPE, treftl); + } + } + + // eliminate redudant typerefs + Type[] treftypes = elimRedundant(treftl.toArrayReverse(), false); + if (treftypes.length != 1 || glbType.members.elems != Scope.Entry.NONE) { + // step 4: replace all abstract types by their lower bounds. + boolean hasAbstract = false; + for (int i = 0; i < treftypes.length; i++) { + if (treftypes[i].unalias().symbol().kind == TYPE) + hasAbstract = true; + } + if (hasAbstract) { + treftl = Type.List.EMPTY; + for (int i = 0; i < treftypes.length; i++) { + if (treftypes[i].unalias().symbol().kind == TYPE) + treftl = new Type.List(treftypes[i].loBound(), treftl); + else + treftl = new Type.List(treftypes[i], treftl); + } + treftypes = elimRedundant(treftl.toArrayReverse(), false); + } + } + + if (treftypes.length != 1) { + // step 5: if there are conflicting instantiations of same + // class, replace them by lower bound. + Type lb = NoType; + for (int i = 0; + i < treftypes.length && + lb != Global.instance.definitions.ALL_TYPE; + i++) { + for (int j = 0; j < i; j++) { + if (treftypes[j].symbol() == treftypes[i].symbol()) + lb = treftypes[i].loBound(); + } + } + if (lb != NoType) return lb; + } + + if (treftypes.length == 1 && glbType.members.elems == Scope.Entry.NONE) { + return treftypes[0]; + } else { + glbType.parts = treftypes; + return glbType; + } + } + + private static boolean setGlb(Scope result, Scope[] ss, Type glbThisType) { + for (int i = 0; i < ss.length; i++) + for (Scope.Entry e = ss[i].elems; e != Scope.Entry.NONE; e = e.next) + if (!addMember(result, e.sym, glbThisType)) return false; + return true; } + private static boolean addMember(Scope s, Symbol sym, Type glbThisType) { + Type syminfo = sym.info().substThis(sym.owner(), glbThisType); + Scope.Entry e = s.lookupEntry(sym.name); + if (e == Scope.Entry.NONE) { + Symbol sym1 = sym.cloneSymbol(); + sym1.setOwner(glbThisType.symbol()); + sym1.setInfo(syminfo); + s.enter(sym1); + return true; + } else { + Type einfo = e.sym.info(); + if (einfo.isSameAs(syminfo)) { + return true; + } else if (einfo.isSubType(syminfo) && sym.kind != ALIAS) { + return true; + } else if (syminfo.isSubType(einfo) && e.sym.kind != ALIAS) { + e.sym.setInfo(syminfo); + return true; + } else if (sym.kind == VAL && e.sym.kind == VAL || + sym.kind == TYPE && e.sym.kind == TYPE) { + e.sym.setInfo(glb(new Type[]{einfo, syminfo})); + return true; + } else { + return false; + } + } + } + + // Erasure -------------------------------------------------------------------------- public static Map erasureMap = new MapOnlyTypes() { |