/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * (C) Copyright IBM Corporation 2006-2010. */ package x10.types; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.HashSet; import java.util.Set; import polyglot.ast.Expr; import polyglot.types.ClassDef; import polyglot.types.ClassType; import polyglot.types.ConstructorInstance; import polyglot.types.ErrorRef_c; import polyglot.types.FieldInstance; import polyglot.types.Flags; import polyglot.types.Matcher; import polyglot.types.MemberInstance; import polyglot.types.ParsedClassType_c; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.ContainerType; import polyglot.types.Type; import polyglot.types.TypeObject; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.types.Context; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.util.Transformation; import polyglot.util.TransformingList; import polyglot.util.TypedList; import polyglot.util.CollectionUtil; import polyglot.visit.InnerClassRemover; import x10.util.CollectionFactory; import x10.constraint.XFailure; import x10.constraint.XVar; import x10.types.constraints.CConstraint; import x10.types.constraints.ConstraintManager; import x10.types.matcher.Subst; /** 08/11/09 * * An X10ParsedClassType_c represents a type C[T1,..., Tn], where * C is a class and T1,..., Tn are type parameters. Almost all the information * supplied by an X10ParsedClassType_c is obtained from the x10ClassDef(), a reference * to the ClassDef object with which this object is created and that represents the * underlying class definition. * * <p> This class is used to represent information parsed from both structs and classes. * * @author vj */ public class X10ParsedClassType_c extends ParsedClassType_c implements X10ParsedClassType { private static final long serialVersionUID = -647880315275370901L; TypeParamSubst cacheSubst; // "subst" is just an auxiliary structure (cached to improve performance). It represents the typeArguments (thus it is nullified when assigning to typeArguments). // We ignore all constraints (we only handle generics) private Set<X10ParsedClassType_c> cacheDirectSupertypes = null; private Set<X10ParsedClassType_c> cacheAllSupertypes = null; private ArrayList<MethodInstance> cacheAllMethods = null; private void clearCache() { cacheSubst = null; cacheDirectSupertypes = null; cacheAllSupertypes = null; cacheAllMethods = null; } private void calcSuperTypes() { cacheDirectSupertypes = CollectionFactory.newHashSet(); final Type superClass_ = superClass(); if (superClass_ !=null) { final X10ParsedClassType_c superBase = Types.myBaseType(superClass_); if (superBase!=null) cacheDirectSupertypes.add(superBase); } for (Type tn : interfaces()) { final X10ParsedClassType_c superInterfaceBase = Types.myBaseType(tn); if (superInterfaceBase!=null) cacheDirectSupertypes.add(superInterfaceBase); } cacheAllSupertypes = CollectionFactory.newHashSet(cacheDirectSupertypes); for (X10ParsedClassType_c t : cacheDirectSupertypes) cacheAllSupertypes.addAll(t.allSuperTypes(false)); } public Set<X10ParsedClassType_c> directSuperTypes() { if (cacheDirectSupertypes==null) calcSuperTypes(); return cacheDirectSupertypes; } public Set<X10ParsedClassType_c> allSuperTypes(boolean includingMe) { if (cacheAllSupertypes==null) calcSuperTypes(); Set<X10ParsedClassType_c> res = cacheAllSupertypes; if (includingMe) { res = new HashSet<X10ParsedClassType_c>(res); res.add(this); } return res; } /** * @return all methods defined in the class/interface including all inherited methods */ private final static boolean SHOULD_CACHE_ALL_METHODS = false; public ArrayList<MethodInstance> getAllMethods() { if (cacheAllMethods!=null) return cacheAllMethods; ArrayList<MethodInstance> res = new ArrayList<MethodInstance>(methods()); for (X10ParsedClassType_c supertype : allSuperTypes(false)) // using "false" because I already added my methods() res.addAll(supertype.methods()); if (SHOULD_CACHE_ALL_METHODS) cacheAllMethods = res; return res; } public int hashCode() { return def.hashCode(); } @Override public boolean equalsImpl(TypeObject o) { if (o == this) return true; if (o == null) return false; if (o instanceof X10ParsedClassType_c) { X10ParsedClassType_c t = (X10ParsedClassType_c) o; if (! flags().equals(t.flags())) return false; if (def != t.def) { if (def == null || t.def == null) return false; else if (! def.equals(t.def)) return false; } if (typeArguments != t.typeArguments) { if (typeArguments == null) return t.typeArguments == null || t.typeArguments.isEmpty(); else if (t.typeArguments == null) return typeArguments.isEmpty(); else if (! typeArguments.equals(t.typeArguments)) return false; } return true; } return false; } public X10ParsedClassType_c copy() { X10ParsedClassType_c n = (X10ParsedClassType_c) super.copy(); n.clearCache(); return n; } public TypeParamSubst subst() { if (cacheSubst == null) { List<Type> typeArguments = new ArrayList<Type>(); List<ParameterType> typeParameters = new ArrayList<ParameterType>(); for (X10ParsedClassType_c c = this; c != null; c = (X10ParsedClassType_c) c.container()) { X10ClassDef cdef = c.x10Def(); List<ParameterType> tp = cdef.typeParameters(); List<Type> ta = c.typeArguments; // [DC] ta == null can happen if the type is used to access a static member // don't add substitutions in this case if (ta != null) { assert ta.size() == tp.size(); //if (!tp.isEmpty() && !ta.isEmpty()) { typeArguments.addAll(ta); typeParameters.addAll(tp); //} } if (!c.isMember() || c.flags().isStatic()) break; } //if (typeArguments.isEmpty()) typeParameters = new ArrayList<ParameterType>(); assert typeArguments.size() == typeParameters.size(); cacheSubst = new TypeParamSubst((TypeSystem) ts, typeArguments, typeParameters); } return cacheSubst; } public boolean isMissingTypeArguments() { List<ParameterType> tp = x10Def().typeParameters(); return (!tp.isEmpty() && (typeArguments == null || typeArguments.size() != tp.size())); } public X10ParsedClassType_c(X10ClassDef def) { super(def); clearCache(); } public X10ParsedClassType_c(TypeSystem ts, Position pos, Position errorPos, Ref<? extends X10ClassDef> def) { super(ts, pos, errorPos, def); clearCache(); } public Type setFlags(Flags f) { X10ParsedClassType_c c = (X10ParsedClassType_c) this.copy(); c.flags = flags().set(f); /*if (xf.isRooted() || xf.isStruct()) { X10ParsedClassType_c c = (X10ParsedClassType_c) this.copy(); if (c.flags == null) c.flags = X10Flags.toX10Flags(c.def().flags()); if (c.flags == null) c.flags = X10Flags.toX10Flags(Flags.NONE); f.s c.flags = xf.isRooted() ? (xf.isStruct() ? X10Flags.toX10Flags(c.flags).Rooted().Struct() : X10Flags.toX10Flags(c.flags).Rooted()) : ((xf.isStruct()) ? X10Flags.toX10Flags(c.flags).Struct() : c.flags); return c; }*/ return c; } /** Property initializers, used in annotations. */ List<Expr> propertyInitializers; public List<Expr> propertyInitializers() { if (propertyInitializers == null) return Collections.<Expr>emptyList(); return Collections.unmodifiableList(propertyInitializers); } public Expr propertyInitializer(int i) { return propertyInitializers().get(i); } public X10ClassType propertyInitializers(List<Expr> inits) { X10ParsedClassType_c n = (X10ParsedClassType_c) copy(); n.propertyInitializers = inits; return n; } public List<Type> annotations() { return X10TypeObjectMixin.annotations(this); } public List<Type> annotationsMatching(Type t) { return X10TypeObjectMixin.annotationsMatching(this, t); } protected SemanticException realClauseInvalid; private SemanticException error; public SemanticException error() { return error; } public X10ParsedClassType error(SemanticException e) { X10ParsedClassType_c n = (X10ParsedClassType_c) copy(); n.error = e; return n; } public X10ClassType container() { return (X10ClassType) super.container(); } public X10ParsedClassType container(ContainerType container) { return (X10ParsedClassType) super.container(container); } public X10ClassDef x10Def() { return (X10ClassDef) def(); } public boolean isJavaType() { return def().fromJavaClassFile(); } public boolean hasParams() { return x10Def().typeParameters() != null && x10Def().typeParameters().size() != 0; } @Override public Type superClass() { Type sup = super.superClass(); Type base = Types.baseType(sup); if (base instanceof X10ClassType) { XVar supVar = ((X10ClassType) base).x10Def().thisVar(); XVar thisVar = x10Def().thisVar(); try { sup = Subst.subst(sup, thisVar, supVar); } catch (SemanticException e) { } } TypeParamSubst subst = subst(); return subst.reinstantiate(sup); } @Override public List<Type> interfaces() { List<Type> interfaces = super.interfaces(); List<Type> newInterfaces = new ArrayList<Type>(interfaces.size()); for (Type sup : interfaces) { Type base = Types.baseType(sup); if (base instanceof X10ClassType) { XVar supVar = ((X10ClassType) base).x10Def().thisVar(); XVar thisVar = x10Def().thisVar(); try { sup = Subst.subst(sup, thisVar, supVar); } catch (SemanticException e) { } } newInterfaces.add(sup); } TypeParamSubst subst = subst(); return subst.reinstantiate(newInterfaces); } public boolean isIdentityInstantiation() { TypeParamSubst subst = subst(); return subst.isIdentityInstantiation(); } @Override public List<FieldInstance> fields() { TypeParamSubst subst = subst(); return subst.reinstantiate(super.fields()); } @Override public List<MethodInstance> methods() { TypeParamSubst subst = subst(); return subst.reinstantiate(super.methods()); } @Override public List<ConstructorInstance> constructors() { TypeParamSubst subst = subst(); return subst.reinstantiate(super.constructors()); } @Override public List<MemberInstance<?>> members() { TypeParamSubst subst = subst(); return subst.reinstantiate(super.members()); } @Override public List<ClassType> memberClasses() { TypeParamSubst subst = subst(); return subst.reinstantiate(super.memberClasses()); } public static class X10FieldAsTypeTransform implements Transformation<X10FieldDef, FieldInstance> { public FieldInstance transform(X10FieldDef def) { return def.asInstance(); } } public List<FieldInstance> definedProperties() { return new TransformingList<X10FieldDef, FieldInstance>(x10Def().properties(), new X10FieldAsTypeTransform()); } // TODO: vj 08/11/09. Why are properties not obtained through the ClassDef, just like // other class members? public List<FieldInstance> properties() { Type superType = superClass(); if (superType instanceof X10ClassType) { List<FieldInstance> l = ((X10ClassType) superType).properties(); List<FieldInstance> l2 = new ArrayList<FieldInstance>(); l2.addAll(l); l2.addAll(definedProperties()); return l2; } return definedProperties(); } public List<Type> typeMembers() { List<Type> l = new TransformingList<TypeDef, Type>(x10Def().memberTypes(), new TypeDefAsMacroTypeTransform()); TypeParamSubst subst = subst(); return subst.reinstantiate(l); } List<Type> typeArguments; public List<Type> typeArguments() { if (isJavaType()) { return Collections.<Type>emptyList(); // Java generic classes are "raw" (erased) } return typeArguments; } /** * thisVar is set based on the types used to instantiate this type. All * the types used must agree on their thisVar. That is the thisVar * for this type. */ public X10ParsedClassType typeArguments(List<Type> typeArgs) { if (typeArgs == this.typeArguments) return this; X10ParsedClassType_c n = (X10ParsedClassType_c) copy(); if (typeArgs == null) { n.typeArguments = null; } else { n.typeArguments = TypedList.copyAndCheck(typeArgs, Type.class, false); try { n.thisVar = Types.getThisVar(typeArgs); } catch (XFailure z) { throw new InternalCompilerError(z.toString() + " for type " + this); } } n.clearCache(); return n; } @Override public Type memberTypeMatching(Matcher<Type> matcher) { Type n = super.memberTypeMatching(matcher); if (n != null) return n; n = typeMemberMatching(matcher); if (n != null) return n; return null; } public MacroType typeMemberMatching(Matcher<Type> matcher) { for (Type t : typeMembers()) { if (t instanceof MacroType) { MacroType mt = (MacroType) t; try { Type n = matcher.instantiate(mt); if (n instanceof MacroType) return (MacroType) n; } catch (SemanticException e) { } } } return null; } public String typeToString() { StringBuffer sb = new StringBuffer(); /*if (flags() != null) { X10Flags f = X10Flags.toX10Flags(flags()); }*/ // sb.append(flags().toString()).append(" "); String sup = super.typeToString(); sb.append(sup); if (propertyInitializers != null) { String s = propertyInitializers.toString(); sb.append("(").append(s.substring(1, s.length()-1)).append(")"); return sb.toString(); } if (typeArguments != null && ! typeArguments.isEmpty()) { sb.append(typeArguments.toString()); } return sb.toString(); } public boolean isX10Struct() { return flags().isStruct(); } public Type makeX10Struct() { if (isX10Struct()) return this; X10ParsedClassType_c c = (X10ParsedClassType_c) copy(); c.setFlags(flags().Struct()); return c; } public boolean equalsNoFlag(Type o) { if (! (o instanceof X10ParsedClassType_c)) return false; X10ParsedClassType_c other = (X10ParsedClassType_c) o; return this == o; } XVar thisVar; public XVar thisVar() { return thisVar; } CConstraint xClause; //todo: is it mutated? it it used? public CConstraint getXClause() { if (xClause == null) { xClause = ConstraintManager.getConstraintSystem().makeCConstraint(); try { xClause.setThisVar(Types.getThisVar(typeArguments())); } catch (XFailure f) { xClause.setInconsistent(); } } return xClause; } public boolean isValid() { return !(def instanceof ErrorRef_c<?>); } @Override public boolean isReference() { return !isX10Struct(); } public X10ParsedClassType instantiateTypeParametersExplicitly() { X10ParsedClassType pct = this; List<ParameterType> typeParameters = pct.x10Def().typeParameters(); List<Type> typeArguments = pct.typeArguments(); if (typeArguments == null) typeArguments = new ArrayList<Type>(); if (InnerClassRemover.isInner(pct.def())) { X10ParsedClassType container = ((X10ParsedClassType) pct.container()).instantiateTypeParametersExplicitly(); if (container != pct.container()) { pct = pct.container(container); } if (typeArguments.size() < typeParameters.size()) { typeArguments = new ArrayList<Type>(typeArguments); for (int i = typeArguments.size(); i < typeParameters.size(); i++) { typeArguments.add(typeParameters.get(i)); } } if (typeArguments != pct.typeArguments()) { pct = pct.typeArguments(typeArguments); } pct = container.subst().reinstantiate(pct); } if (!typeParameters.isEmpty() && pct.typeArguments()==null) { pct = pct.typeArguments(new ArrayList<Type>(typeParameters)); } return pct; } }