/* * Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.tools.code; import org.visage.tools.comp.VisageDefs; import static org.visage.tools.code.VisageTypeRepresentation.*; import com.sun.tools.mjavac.code.*; import com.sun.tools.mjavac.util.*; import com.sun.tools.mjavac.code.Type.*; import java.util.HashMap; import org.visage.tools.tree.*; import com.sun.tools.mjavac.code.Symbol.*; import com.sun.tools.mjavac.jvm.ClassWriter; import static com.sun.tools.mjavac.code.Kinds.*; import static com.sun.tools.mjavac.code.Flags.*; import static com.sun.tools.mjavac.code.TypeTags.*; /** * * @author bothner */ public class VisageTypes extends Types { VisageSymtab syms; ClassWriter writer; private HashMap<ClassSymbol, VisageClassDeclaration> visageClasses; public static void preRegister(final Context context) { if (context.get(typesKey) == null) context.put(typesKey, new Context.Factory<Types>() { public Types make() { return new VisageTypes(context); } }); } public static void preRegister(final Context context, VisageTypes types) { context.put(typesKey, types); } public static VisageTypes instance(Context context) { VisageTypes instance = (VisageTypes) context.get(typesKey); if (instance == null) instance = new VisageTypes(context); return instance; } protected VisageTypes(Context context) { super(context); syms = (VisageSymtab) VisageSymtab.instance(context); writer = ClassWriter.instance(context); } public boolean isNullable(Type type) { return !type.isPrimitive() && type != syms.visage_StringType && type != syms.visage_DurationType && type != syms.visage_LengthType && type != syms.visage_AngleType && type != syms.visage_ColorType; } public boolean isSequence(Type type) { return type != Type.noType && type != null && type.tag != TypeTags.ERROR && type.tag != TypeTags.METHOD && type.tag != TypeTags.FORALL && erasure(type) == syms.visage_SequenceTypeErasure; } public boolean isSyntheticBuiltinsFunction(Symbol sym) { return sym != null && sym.kind == Kinds.MTH && (sym.flags_field & VisageFlags.FUNC_IS_BUILTINS_SYNTH) != 0; } public boolean isSyntheticPointerFunction(Symbol sym) { return sym != null && sym.kind == Kinds.MTH && (sym.flags_field & VisageFlags.FUNC_POINTER_MAKE) != 0; } public boolean isArrayOrSequenceType(Type type) { return isArray(type) || isSequence(type); } public Type arrayOrSequenceElementType(Type type) { return isArray(type) ? elemtype(type) : elementType(type); } public Type sequenceType(Type elemType) { return sequenceType(elemType, true); } public Type sequenceType(Type elemType, boolean withExtends) { elemType = boxedTypeOrType(elemType); if (withExtends) elemType = new WildcardType(elemType, BoundKind.EXTENDS, syms.boundClass); return applySimpleGenericType(syms.visage_SequenceType, elemType); } public Type applySimpleGenericType(Type base, Type... parameter) { List<Type> actuals = List.from(parameter); Type clazzOuter = base.getEnclosingType(); return new ClassType(clazzOuter, actuals, base.tsym); } public VisageTypeRepresentation typeRep(Type type) { TypeSymbol tsym = type.tsym; if (tsym == syms.booleanType.tsym) return TYPE_REPRESENTATION_BOOLEAN; if (tsym == syms.charType.tsym) return TYPE_REPRESENTATION_CHAR; if (tsym == syms.byteType.tsym) return TYPE_REPRESENTATION_BYTE; if (tsym == syms.shortType.tsym) return TYPE_REPRESENTATION_SHORT; if (tsym == syms.intType.tsym) return TYPE_REPRESENTATION_INT; if (tsym == syms.longType.tsym) return TYPE_REPRESENTATION_LONG; if (tsym == syms.floatType.tsym) return TYPE_REPRESENTATION_FLOAT; if (tsym == syms.doubleType.tsym) return TYPE_REPRESENTATION_DOUBLE; if (isSequence(type)) { return TYPE_REPRESENTATION_SEQUENCE; } else { return TYPE_REPRESENTATION_OBJECT; } } public Type arraySequenceType(Type elemType) { if (elemType.isPrimitive()) { String tname = typeRep(elemType).prefix(); return syms.enterClass(VisageDefs.sequence_PackageString + "." + tname + "ArraySequence"); } Type seqtype = syms.enterClass("org.visage.runtime.sequence.ObjectArraySequence"); return applySimpleGenericType(seqtype, elemType); } public Type boxedElementType(Type seqType) { Type elemType = seqType.getTypeArguments().head; if (elemType instanceof CapturedType) elemType = ((CapturedType) elemType).wildcard; if (elemType instanceof WildcardType) elemType = ((WildcardType) elemType).type; if (elemType == null) return syms.visage_AnyType; return elemType; } public Type elementType(Type seqType) { Type elemType = boxedElementType(seqType); Type unboxed = unboxedType(elemType); if (unboxed.tag != TypeTags.NONE) elemType = unboxed; return elemType; } public Type unboxedTypeOrType(Type t) { Type ubt = unboxedType(t); return ubt==Type.noType? t : ubt; } public Type boxedTypeOrType(Type t) { return (t.isPrimitive() || t == syms.voidType)? boxedClass(t).type : t; } public Type elementTypeOrType(Type t) { return isSequence(t) ? elementType(t) : t; } public Type makeUnionType(Type s, Type t) { Type lub = lub(s.baseType(), t.baseType()); if (lub.isCompound()) { //members of the compound type could not be ordered properly //due to the fact that Visage allows MI through mixins //the compound supertype should always be a Visage class //while the superinterfaces should be mixins Type clazz = null; ListBuffer<Type> interfaces = new ListBuffer<Type>(); ListBuffer<Type> mixins = new ListBuffer<Type>(); for (Type st : interfaces(lub).prepend(supertype(lub))) { if (isMixin(st.tsym)) mixins.append(st); else if (st.isInterface()) interfaces.append(st); else clazz = st; } List<Type> supertypes = interfaces.toList().prependList(mixins.toList()); if (clazz != null) supertypes = supertypes.prepend(clazz); lub = makeCompoundType(supertypes); } return lub; } @Override public boolean isSubtype(Type t, Type s, boolean capture) { boolean b = super.isSubtype(t, s, capture); if (!b && s.tag == CLASS && s.isCompound()) { for (Type s2 : interfaces(s).prepend(supertype(s))) { if (!isSubtype(t, s2, capture)) return false; } return true; } else return b; } @Override public Type asSuper(Type t, Symbol sym) { return asSuper.visit(t, sym); } // where private SimpleVisitor<Type,Symbol> asSuper = new SimpleVisitor<Type,Symbol>() { public Type visitType(Type t, Symbol sym) { return null; } @Override public Type visitClassType(ClassType t, Symbol sym) { if (t.tsym == sym) return t; for (Type st : supertypes(t)) { if (st.tag == CLASS || st.tag == TYPEVAR || st.tag == ERROR) { Type x = asSuper(st, sym); if (x != null) return x; } } return null; } @Override public Type visitArrayType(ArrayType t, Symbol sym) { return isSubtype(t, sym.type) ? sym.type : null; } @Override public Type visitTypeVar(TypeVar t, Symbol sym) { if (t.tsym == sym) return t; else return asSuper(t.bound, sym); } @Override public Type visitErrorType(ErrorType t, Symbol sym) { return t; } }; @Override public boolean isConvertible (Type t, Type s, Warner warn) { if (super.isConvertible(t, s, warn)) return true; if (isSequence(t) && isArray(s)) return isConvertible(elementType(t), elemtype(s), warn); if (isArray(t) && isSequence(s)) return isConvertible(elemtype(t), elementType(s), warn); if (isSequence(t) && isSequence(s)) return isConvertible(elementType(t), elementType(s), warn); //sequence promotion conversion if (isSequence(s) && !isSequence(t)) { return isConvertible(sequenceType(t), s, warn); } // Allow all numeric conversion, for now (some should warn) if (isNumeric(t) && isNumeric(s)) { return true; } if (t == syms.intType && s == syms.charType) return true; return false; } @Override public boolean isCastable(Type t, Type s, Warner warn) { //if source is a sequence and target is neither a sequence nor Object return false if (isSequence(t) && !(isSequence(s) || s.tag == TypeTags.ARRAY) && s != syms.objectType && s != syms.botType) { return false; } //cannot cast from null to a value type (non-null by default) and vice-versa if ((s == syms.botType && t.isPrimitive()) || (t == syms.botType && s.isPrimitive())) { return false; } Type target = isSequence(s) ? elementType(s) : s.tag == TypeTags.ARRAY ? ((ArrayType) s).elemtype : s; Type source = isSequence(t) ? elementType(t) : t.tag == TypeTags.ARRAY ? ((ArrayType) t).elemtype : t; if (!source.isPrimitive()) target = boxedTypeOrType(target); if (!target.isPrimitive()) source = boxedTypeOrType(source); if (source == syms.botType || target == syms.botType) return true; return isCastableNoConversion(source, target, warn); } public boolean isCastableNoConversion(Type source, Type target, Warner warn) { if (isSequence(source) != isSequence(target) && !isSameType(source, syms.objectType) && !isSameType(target, syms.objectType)) return false; if (source.isPrimitive() && !target.isPrimitive() && isSubtype(boxedClass(source).type, target)) return true; if (target.isPrimitive() && !source.isPrimitive() && isSubtype(boxedClass(target).type, source)) return true; boolean isSourceFinal = (source.tsym.flags() & FINAL) != 0; boolean isTargetFinal = (target.tsym.flags() & FINAL) != 0; if (isMixin(source.tsym) && isMixin(target.tsym)) return true; else if (isMixin(source.tsym) && !isTargetFinal || (target.isInterface() && !isSequence(target))) return true; else if (isMixin(target.tsym) && !isSourceFinal || (target.isInterface() && !isSequence(target))) return true; else //conversion between two primitives/Java classes return super.isCastable(source, target, warn); } public boolean isMixin(Symbol sym) { if (! (sym instanceof VisageClassSymbol)) return false; sym.complete(); return (sym.flags_field & VisageFlags.MIXIN) != 0; } public boolean isVisageClass(Symbol sym) { if (! (sym instanceof VisageClassSymbol)) return false; sym.complete(); return (sym.flags_field & VisageFlags.VISAGE_CLASS) != 0; } public boolean isVisageFunction(Type t) { return (t instanceof FunctionType); } public void addVisageClass(ClassSymbol csym, VisageClassDeclaration cdecl) { if (visageClasses == null) { visageClasses = new HashMap<ClassSymbol, VisageClassDeclaration>(); } csym.flags_field |= VisageFlags.VISAGE_CLASS; visageClasses.put(csym, cdecl); } public VisageClassDeclaration getVisageClass (ClassSymbol csym) { return visageClasses.get(csym); } /** The implementation of this (abstract) symbol in class origin; * null if none exists. Synthetic methods are not considered * as possible implementations. * Based on the Javac implementation method in MethodSymbol, * but modified to handle multiple inheritance. */ public MethodSymbol implementation(MethodSymbol msym, TypeSymbol origin, boolean checkResult) { msym.complete(); if (origin instanceof VisageClassSymbol) { VisageClassSymbol c = (VisageClassSymbol) origin; for (Scope.Entry e = c.members().lookup(msym.name); e.scope != null; e = e.next()) { if (e.sym.kind == MTH) { MethodSymbol m = (MethodSymbol) e.sym; m.complete(); if (m.overrides(msym, origin, this, checkResult) && (m.flags() & SYNTHETIC) == 0) return m; } } List<Type> supers = supertypes(c.type); for (List<Type> l = supers; l.nonEmpty(); l = l.tail) { MethodSymbol m = implementation(msym, l.head.tsym, checkResult); if (m != null) return m; } return null; } else return msym.implementation(origin, this, checkResult); } /** A replacement for MethodSymbol.overrides. */ public boolean overrides(Symbol sym, Symbol _other, TypeSymbol origin, boolean checkResult) { if (sym.isConstructor() || _other.kind != MTH) return false; if (sym == _other) return true; MethodSymbol other = (MethodSymbol)_other; // assert types.asSuper(origin.type, other.owner) != null; Type mt = this.memberType(origin.type, sym); Type ot = this.memberType(origin.type, other); return this.isSubSignature(mt, ot) && (!checkResult || this.resultSubtype(mt, ot, Warner.noWarnings)); } /** * Returns a list of all supertypes of t, without duplicates, where supertypes * are listed according to the order in which they appear in t's extends clause. * This method is used in order to implicitly resolve mixin conflicts. * * @param t the type for which the supertypes list is to be retrieved * @return list of ordered supertypes */ public List<Type> supertypesClosure(Type t) { return supertypesClosure(t, false, false); } public List<Type> supertypesClosure(Type t, boolean includeThis) { return supertypesClosure(t, includeThis, false); } public List<Type> supertypesClosure(Type t, boolean includeThis, boolean ascending) { List<Type> closure = supertypesClosure(t, ListBuffer.<Type>lb(), ascending); return includeThis ? closure : ascending ? closure.reverse().tail.reverse() : closure.tail; } //where private List<Type> supertypesClosure(Type t, ListBuffer<Type> seenTypes, boolean ascending) { if (t == null || t.tag == NONE || seenTypes.contains(t)) { return List.nil(); } else { seenTypes.append(t); List<Type> closure = supertypesClosure(supertype(t), seenTypes, ascending); for (Type i : interfaces(t)) { closure = closure.appendList(supertypesClosure(i, seenTypes, ascending)); } closure = ascending ? closure.append(t) : closure.prepend(t); return closure; } } public List<Type> supertypes(Type t) { Type sup = supertype(t); return (sup == null || sup.tag == NONE) ? interfaces(t) : interfaces(t).prepend(sup); } public void clearCaches() { visageClasses = null; } public boolean isNumeric(Type type) { return (isSameType(type, syms.visage_ByteType) || isSameType(type, syms.visage_ShortType) || isSameType(type, syms.visage_IntegerType) || isSameType(type, syms.visage_LongType) || isSameType(type, syms.visage_FloatType) || isSameType(type, syms.visage_DoubleType)); } public List<String> toVisageString(List<Type> ts) { List<String> buf = List.nil(); for (Type t : ts) { buf = buf.prepend(toVisageString(t)); } return buf.reverse(); } public String toVisageString(Type type) { StringBuilder buffer = new StringBuilder(); typePrinter.visit(type, buffer); return buffer.toString(); } SimpleVisitor typePrinter = new SimpleVisitor<Void, StringBuilder>() { public Void visitType(Type t, StringBuilder buffer) { String s = null; switch (t.tag) { case NONE: s = "<unknown>"; break; case UNKNOWN: s = "Object"; break; case BYTE: s = "Byte"; break; case SHORT: s = "Short"; break; case INT: s = "Integer"; break; case LONG: s = "Long"; break; case FLOAT: s = "Number"; break; case DOUBLE: s = "Double"; break; case CHAR: s = "Character"; break; case BOOLEAN: s = "Boolean"; break; default: s = t.toString(); break; } buffer.append(s); return null; } @Override public Void visitMethodType(MethodType t, StringBuilder buffer) { if (t.getReturnType() == null) { buffer.append("function(?):?"); return null; } buffer.append("function("); List<Type> args = t.getParameterTypes(); for (List<Type> l = args; l.nonEmpty(); l = l.tail) { if (l != args) { buffer.append(","); } buffer.append(":"); visit(l.head, buffer); } buffer.append("):"); visit(t.getReturnType(), buffer); return null; } @Override public Void visitArrayType(ArrayType t, StringBuilder buffer) { buffer.append("nativearray of "); visit(elemtype(t), buffer); return null; } @Override public Void visitClassType(ClassType t, StringBuilder buffer) { if (isSameType(t, syms.stringType)) buffer.append("String"); else if (isSameType(t, syms.objectType)) buffer.append("Object"); else if (isSequence(t)) { if (t != syms.visage_EmptySequenceType) { visit(elementType(t), buffer); } buffer.append("[]"); } else if (t instanceof FunctionType) { visitMethodType(t.asMethodType(), buffer); } else if (t.isCompound()) { visit(supertype(t), buffer); } else buffer.append(t.toString()); return null; } }; public String toVisageString(MethodSymbol sym, List<VarSymbol> params) { StringBuilder buffer = new StringBuilder(); if ((sym.flags() & BLOCK) != 0) buffer.append(sym.owner.name); else { buffer.append(sym.name == sym.name.table.init ? sym.owner.name : sym.name); if (sym.type != null) { buffer.append('('); // FUTURE: check (flags() & VARARGS) != 0 List<Type> args = sym.type.getParameterTypes(); for (List<Type> l = args; l.nonEmpty(); l = l.tail) { if (l != args) buffer.append(","); if (params != null && params.nonEmpty()) { VarSymbol param = params.head; if (param != null) buffer.append(param.name); params = params.tail; } buffer.append(":"); buffer.append(toVisageString(l.head)); } buffer.append(')'); } } return buffer.toString(); } public String location (Symbol sym, Type site) { while ((sym.owner.flags() & BLOCK) != 0 || syms.isRunMethod(sym.owner)) sym = sym.owner; return sym.location(site, this); } public String location (Symbol sym) { while ((sym.owner.flags() & BLOCK) != 0 || syms.isRunMethod(sym.owner)) sym = sym.owner; return sym.location(); } /** * Computes a type which is suitable as a variable inferred type. * This step is needed because the inferred type can contain captured * types which makes the inferred type too specific. * * @param t the type to be normalized * @return the normalized type */ public Type normalize(Type t) { class TypeNormalizer extends SimpleVisitor<Type, Boolean> { @Override public Type visitTypeVar(TypeVar t, Boolean preserveWildcards) { return visit(t.getUpperBound(), preserveWildcards); } @Override public Type visitCapturedType(CapturedType t, Boolean preserveWildcards) { return visit(t.wildcard, preserveWildcards); } @Override public Type visitWildcardType(WildcardType t, Boolean preserveWildcards) { Type bound2 = visit(upperBound(t), preserveWildcards); if (!preserveWildcards) { return bound2; } else if (t.kind != BoundKind.SUPER && !isSameType(bound2, upperBound(t))) { t = new WildcardType(bound2, BoundKind.EXTENDS, syms.boundClass); } return t; } @Override public Type visitClassType(ClassType t, Boolean preserveWildcards) { List<Type> args2 = visit(t.getTypeArguments(), true); Type encl2 = visit(t.getEnclosingType(), false); if (!isVisageFunction(t) && (!isSameTypes(args2, t.getTypeArguments()) || !isSameType(encl2, t.getEnclosingType()))) { t = new ClassType(encl2, args2, t.tsym); } return t; } public Type visitType(Type t, Boolean preserveWildcards) { if (t == syms.botType) { return syms.objectType; } else if (isSameType(t, syms.visage_EmptySequenceType)) { return sequenceType(syms.objectType); } else if (t == syms.unreachableType) { return syms.objectType; } else { return t; } } public List<Type> visit(List<Type> ts, Boolean preserveWildcards) { ListBuffer<Type> buf = ListBuffer.lb(); for (Type t : ts) { buf.append(visit(t, preserveWildcards)); } return buf.toList(); } } return new TypeNormalizer().visit(t, false); } public String toSignature(Type t) { return writer.typeSig(t).toString(); } }