/* * 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.Iterator; import java.util.List; import polyglot.types.FunctionInstance_c; import polyglot.types.JavaArrayType; import polyglot.types.Context; import polyglot.types.DerefTransform; import polyglot.types.ErrorRef_c; import polyglot.types.FieldDef; import polyglot.types.FieldInstance; import polyglot.types.Flags; import polyglot.types.LocalDef; import polyglot.types.LocalInstance; import polyglot.types.MemberDef; import polyglot.types.MethodDef; import polyglot.types.Name; import polyglot.types.JavaPrimitiveType; import polyglot.types.ProcedureInstance; import polyglot.types.Ref; import polyglot.types.SemanticException; import polyglot.types.ContainerType; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.types.UpcastTransform; import polyglot.util.CollectionUtil; import x10.util.CollectionFactory; import polyglot.util.InternalCompilerError; import polyglot.util.Position; import polyglot.util.Transformation; import polyglot.util.TransformingList; import x10.constraint.XFailure; import x10.constraint.XVar; import x10.constraint.XTerm; import x10.types.constraints.ConstraintManager; import x10.constraint.XVar; import x10.types.constraints.CConstraint; import x10.types.constraints.CConstraint; import x10.types.constraints.TypeConstraint; import x10.types.matcher.Matcher; import x10.types.MethodInstance; /** * A representation of a MethodInstance. * * @author vj * */ public class MethodInstance_c extends FunctionInstance_c<MethodDef> implements MethodInstance { private static final long serialVersionUID = 3883485772306553465L; public MethodInstance_c(TypeSystem ts, Position pos, Position errorPos, Ref<? extends X10MethodDef> def) { super(ts, pos, errorPos, def); } protected Name name; protected Flags flags; protected ContainerType container; public MethodInstance container(ContainerType container) { if (container == this.container) return this; MethodInstance_c p = (MethodInstance_c) copy(); p.container = container; return p; } public ContainerType container() { if (this.container == null) { return Types.get(def().container()); } return this.container; } public MethodInstance flags(Flags flags) { MethodInstance_c p = (MethodInstance_c) copy(); p.flags = flags; return p; } public Flags flags() { if (this.flags == null) { return def().flags(); } return this.flags; } public MethodInstance name(Name name) { MethodInstance_c p = (MethodInstance_c) copy(); p.name = name; return p; } public Name name() { if (this.name == null) { return def().name(); } return this.name; } @Override public boolean moreSpecific(Type container, ProcedureInstance<MethodDef> p, Context context) { return Types.moreSpecificImpl(container, this, p, context); } public static class NoClauseVariant implements Transformation<Type, Type> { public Type transform(Type o) { if (o instanceof JavaArrayType) { JavaArrayType at = (JavaArrayType) o; return at.base(Types.ref(transform(at.base()))); } if (o instanceof ConstrainedType) { ConstrainedType ct = (ConstrainedType) o; return transform(Types.get(ct.baseType())); } return o; } } @Override public MethodInstance returnType(Type returnType) { return (MethodInstance) super.returnType(returnType); } @Override public MethodInstance returnTypeRef(Ref<? extends Type> returnType) { if (returnType == this.returnType) return this; return (MethodInstance) super.returnTypeRef(returnType); } public List<Type> annotations() { return X10TypeObjectMixin.annotations(this); } public List<Type> annotationsMatching(Type t) { return X10TypeObjectMixin.annotationsMatching(this, t); } XTerm body; public XTerm body() { if (this.body == null) return Types.get(x10Def().body()); return body; } public MethodInstance body(XTerm body) { if (body == this.body) return this; MethodInstance_c n = (MethodInstance_c) copy(); n.body = body; return n; } public Ref <? extends Type> offerType() { return x10Def().offerType(); } public List<Type> typeParameters; public List<Type> typeParameters() { if (this.typeParameters == null) { return new TransformingList<ParameterType, Type>(x10Def().typeParameters(), new UpcastTransform<Type, ParameterType>()); } return typeParameters; } public MethodInstance typeParameters(List<Type> typeParameters) { if (typeParameters == this.typeParameters) return this; MethodInstance_c n = (MethodInstance_c) copy(); n.typeParameters = typeParameters; return n; } public List<LocalInstance> formalNames; public List<LocalInstance> formalNames() { if (this.formalNames == null) { return new TransformingList<LocalDef,LocalInstance>(x10Def().formalNames(), new Transformation<LocalDef,LocalInstance>() { public LocalInstance transform(LocalDef o) { return o.asInstance(); } }); } return formalNames; } public MethodInstance formalNames(List<LocalInstance> formalNames) { if (formalNames == this.formalNames) return this; MethodInstance_c n = (MethodInstance_c) copy(); n.formalNames = formalNames; return n; } public MethodInstance formalTypes(List<Type> formalTypes) { if (formalTypes == this.formalTypes) return this; return (MethodInstance) super.formalTypes(formalTypes); } private SemanticException error; public SemanticException error() { return error; } public MethodInstance error(SemanticException e) { if (e == this.error) return this; MethodInstance_c n = (MethodInstance_c) copy(); n.error = e; return n; } public static void buildSubst(MethodInstance mi, List<XVar> ys, List<XVar> xs, XVar thisVar) { XVar mdThisVar = mi.x10Def().thisVar(); if (mdThisVar != null && mdThisVar != thisVar && ! xs.contains(mdThisVar)) { ys.add(thisVar); xs.add(mdThisVar); } buildSubst(mi.container(), ys, xs, thisVar); } public static void buildSubst(Type t, List<XVar> ys, List<XVar> xs, XVar thisVar) { Type container = Types.baseType(t); if (container instanceof X10ClassType) { X10ClassDef cd = ((X10ClassType) container).x10Def(); XVar cdThisVar = cd.thisVar(); if (cdThisVar != null && cdThisVar != thisVar && ! xs.contains(cdThisVar) ) { ys.add(thisVar); xs.add(cdThisVar); } Type superClass = ((X10ClassType) container).superClass(); if (superClass != null) { buildSubst(superClass, ys, xs, thisVar); } for (Type ti : ((X10ClassType) container).interfaces()) { buildSubst(ti, ys, xs, thisVar); } } } public boolean isPropertyGetter() { ContainerType container = this.container(); assert container instanceof X10ParsedClassType; if (!formalTypes.isEmpty()) return false; for (FieldInstance fi : container.fields()) { FieldDef fd = fi.def(); if (fd instanceof X10FieldDef) { X10FieldDef xfd = (X10FieldDef) fd; if (xfd.isProperty()) { return true; } } } return false; } /* public boolean isSafe() { StructType container = this.container(); assert container instanceof X10ParsedClassType : container + " for " + this; boolean result = ((X10ParsedClassType) container).isSafe(); if (result) return true; X10Flags f = X10Flags.toX10Flags(flags()); result = f.isSafe(); return result; }*/ public X10MethodDef x10Def() { return (X10MethodDef) def(); } public String containerString() { Type container = container(); container = Types.baseType(container); if (container instanceof FunctionType) { return "(" + container.toString() + ")"; } return container.fullName().toString(); } public String toString() { String s = designator() + " " + flags().prettyPrint() + containerString() + "." + signature(); if (! throwTypes().isEmpty()) { s += " throws " + CollectionUtil.listToString(throwTypes()); } if (body != null) s += " = " + body; return s; } public String signature() { StringBuilder sb = new StringBuilder(); Name name = this.name(); sb.append(name != null ? name : def().name()); List<String> params = new ArrayList<String>(); List<Type> typeParameters = this.typeParameters(); if (typeParameters != null) { for (int i = 0; i < typeParameters.size(); i++) { params.add(typeParameters.get(i).toString()); } } else { for (int i = 0; i < x10Def().typeParameters().size(); i++) { params.add(x10Def().typeParameters().get(i).toString()); } } if (params.size() > 0) { sb.append("["); sb.append(CollectionUtil.listToString(params)); sb.append("]"); } List<String> formals = new ArrayList<String>(); List<Type> formalTypes = this.formalTypes(); if (formalTypes != null) { List<LocalInstance> formalNames = this.formalNames(); for (int i = 0; i < formalTypes.size(); i++) { String s = ""; String t = formalTypes.get(i).toString(); if (formalNames != null && i < formalNames.size()) { X10LocalInstance a = (X10LocalInstance) formalNames.get(i); if (a != null && ! a.x10Def().isUnnamed()) s = a.name() + ": " + t; else s = t; } else { s = t; } formals.add(s); } } else { for (int i = 0; i < def().formalTypes().size(); i++) { formals.add(def().formalTypes().get(i).toString()); } } sb.append("("); sb.append(CollectionUtil.listToString(formals)); sb.append(")"); CConstraint guard = this.guard(); if (guard != null) sb.append(guard); else if (x10Def().guard() != null) sb.append(x10Def().guard()); TypeConstraint typeGuard = this.typeGuard(); if (typeGuard != null) sb.append(typeGuard); else if (x10Def().typeGuard() != null) sb.append(x10Def().typeGuard()); Ref<? extends Type> returnType = this.returnTypeRef(); if (returnType != null && returnType.known()) { sb.append(": "); sb.append(returnType); } return sb.toString(); } public MethodInstance throwTypes(List<Type> throwTypes) { return (MethodInstance) super.throwTypes(throwTypes); } /** Returns true iff <this> is the same method as <m> */ public final boolean isSameMethod(MethodInstance m, Context context) { return ts.isSameMethod((MethodInstance) this, m, context); } public final List<MethodInstance> overrides(Context context) { return ts.overrides((MethodInstance) this, context); } Type rightType; /** * Iff this is a zero-ary property method invocation, add the clause * self=term to the return type, where term is body if the method def has * a body, else, term is this.m(). * * Thus the resulting type may have occurrences of this. */ public Type rightType() { TypeSystem xts = (TypeSystem) ts; if (rightType == null) { Type t = returnType(); // If a property method, replace T with T{self==this}. Flags flags = flags(); if (flags.isProperty() && formalTypes.size() == 0) { if (xts.isUnknown(t)) { rightType = t; } else { CConstraint rc = Types.xclause(t); if (rc == null) rc = ConstraintManager.getConstraintSystem().makeCConstraint(); XTerm receiver; if (flags.isStatic()) { receiver = xts.xtypeTranslator().translate(container()); } else { receiver = x10Def().thisVar(); assert receiver != null; } // ### pass in the type rather than letting XField call fi.type(); // otherwise, we'll get called recursively. XTerm self = body(); CConstraint c = rc.copy(); // TODO: handle non-vars, like rail().body if (self == null || ! (self instanceof XVar)) { self = xts.xtypeTranslator().translate(receiver, this); } if (self != null) { c.addSelfBinding(self); } if (! flags.isStatic()) { c.setThisVar((XVar) receiver); } rightType = Types.xclause(Types.baseType(t), c); } } else { rightType = t; } assert rightType != null; } return rightType; } static private String toString( XVar[] ys) { String s = ""; for (XVar x : ys) s += x.toString() + " "; return s; } public boolean isValid() { return !(def instanceof ErrorRef_c<?>); } /** * Leave this method in for historic reasons, to make sure that extensions * modify their code correctly. */ public final boolean canOverride(MethodInstance mj, Context context) { return ts.canOverride((MethodInstance) this, mj, context); } // nobody calls this. public final void checkOverride(MethodInstance mj, Context context) throws SemanticException { ts.checkOverride((MethodInstance) this, mj, context); } public final List<MethodInstance> implemented(Context context) { return ts.implemented((MethodInstance) this, context); } protected MethodInstance origMI; public MethodInstance origMI() { return origMI;} public void setOrigMI(MethodInstance origMI) { this.origMI = origMI; } }