/* * 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.matcher; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import polyglot.types.ClassType; import polyglot.types.ContainerType; import polyglot.types.LocalInstance; import polyglot.types.NullType; import polyglot.types.SemanticException; import polyglot.types.Type; import polyglot.types.TypeSystem; import polyglot.types.Types; import polyglot.types.UnknownType; import x10.constraint.XFailure; import x10.constraint.XTerm; import x10.constraint.XVar; import x10.types.ClosureInstance; import x10.types.ConstrainedType; import x10.types.MacroType; import x10.types.MethodInstance; import x10.types.ParameterType; import x10.types.TypeParamSubst; import x10.types.X10ClassType; import x10.types.X10ConstructorInstance; import x10.types.X10FieldInstance; import x10.types.X10LocalInstance; import x10.types.X10ParsedClassType; import x10.types.constraints.CConstraint; import x10.types.constraints.TypeConstraint; public class Subst { public static Type subst(Type t, Type[] Y, ParameterType[] X) throws SemanticException { assert Y.length == X.length; for (int i = 0; i < X.length; i++) { if (Y[i] == null) throw new SemanticException("Cannot infer type for parameter " + X[i] + "."); t = subst(t, Y[i], X[i]); } return t; } /** * Add in to the constraint for every component of the type t, recursively: * If t is T{c} ===> return addIn(T,in){c,in} * If t is A[T1,..., Tn] ===> return addIn(A,in)[addIn(T1,in),..., addIn(Tn,n)] * If t is X ==> return X{in} * @param t --- The type subjected to the change * @param in --- The constraint to be added * @return -- The type t, with c added to each component (recursively). * @throws XFailure -- If one of the component types is inconsistent. */ public static Type addIn(Type t, CConstraint in) { if (t == null) return null; TypeSystem ts = (TypeSystem) t.typeSystem(); t = ts.expandMacros(t); if (t instanceof NullType) return t; if (t instanceof UnknownType) return t; if (t instanceof ParameterType) { if (in.valid()) return t; return Types.xclause(t, in); } if (ts.isVoid(t)) { return t; } if (t instanceof X10ParsedClassType) { X10ParsedClassType ct = (X10ParsedClassType) t; List<Type> newArgs = new ArrayList<Type>(); if (ct.typeArguments() == null) return ct; for (Type at : ct.typeArguments()) { Type at2 = addIn(at, in); newArgs.add(at2); } return ct.typeArguments(newArgs); } Type base = Types.baseType(t); CConstraint c = Types.xclause(t); if (t==base) assert t != base; base = addIn(base, in); if (c != null) { c = c.copy(); c.addIn(in); } return Types.xclause(base, c); } public static Type project(Type t, XVar v) { if (t == null) return null; TypeSystem ts = (TypeSystem) t.typeSystem(); t = ts.expandMacros(t); if (t instanceof NullType) return t; if (t instanceof UnknownType) return t; if (t instanceof ParameterType) { return t; } if (ts.isVoid(t)) { return t; } if (t instanceof X10ParsedClassType) { X10ParsedClassType ct = (X10ParsedClassType) t; List<Type> newArgs = new ArrayList<Type>(); if (ct.typeArguments() == null) return ct; for (Type at : ct.typeArguments()) { Type at2 = project(at, v); newArgs.add(at2); } return ct.typeArguments(newArgs); } Type base = Types.baseType(t); CConstraint c = Types.xclause(t); if (t == base) assert t != base; base = project(base, v); if (c != null) { c = c.copy().project(v); } return Types.xclause(base, c); } /** * Returns a new type formed from t by substituting y for x. The old type is not modified. * @param t * @param y * @param x * @return * @throws SemanticException */ public static List<Type> subst(List<Type> ts, XTerm[] y, XVar[] x) throws SemanticException { List<Type> result= new ArrayList<Type>(ts.size()); boolean changed = false; for (Type t : ts) { Type nt = subst(t, y, x); if (nt != t) changed = true; result.add(nt); } if (!changed) return ts; return result; } public static Type subst(Type t, XTerm[] y, XVar[] x) throws SemanticException { assert y.length == x.length; if (t == null) return null; TypeSystem ts = (TypeSystem) t.typeSystem(); t = ts.expandMacros(t); Type base = Types.baseType(t); CConstraint c = Types.xclause(t); if (t instanceof X10ParsedClassType) { X10ParsedClassType ct = (X10ParsedClassType) t; if (ct.typeArguments() == null) return ct; List<Type> newArgs = new ArrayList<Type>(); boolean changed = false; for (Type at : ct.typeArguments()) { Type at2 = subst(at, y, x); newArgs.add(at2); if (at2 != at) changed = true; } if (changed && ! newArgs.isEmpty()) return ct.typeArguments(newArgs); } else if (c != null) { CConstraint newC = c; Type newBase = subst(base, y, x); try { newC = newC.substitute(y, x); // newC = newC.saturate(); } catch (XFailure e) { throw new SemanticException("Cannot instantiate formal parameters on actuals."); } if (newBase != base || newC != c) { return Types.xclause(newBase, newC); } } return t; } public static Type subst(Type t, XTerm[] y, XVar[] x, Type[] Y, ParameterType[] X) throws SemanticException { if (t instanceof ConstrainedType) { ConstrainedType ct = (ConstrainedType) t; Type base = Types.get(ct.baseType()); // do not call X10TypeMixin.baseType(ct); that will strip constraints in ct base = subst(base, y, x, Y, X); CConstraint c = Types.get(ct.constraint()); c = subst(c, y, x, Y, X); return Types.xclause(base, c); } if (t instanceof ParameterType) { for (int i = 0; i < X.length; i++) { if (TypeParamSubst.isSameParameter((ParameterType) t, X[i])) return Y[i]; } return t; } if (t instanceof X10ClassType) { X10ClassType ct = (X10ClassType) t; if (ct.isIdentityInstantiation()) { List<Type> args = new ArrayList<Type>(); boolean changed = false; for (Type ti : ct.x10Def().typeParameters()) { Type ti2 = subst(ti, y, x, Y, X); if (ti2 != ti) changed = true; args.add(ti2); } if (changed) return ct.typeArguments(args); return ct; } else { if (ct.typeArguments() == null) return ct; List<Type> args = new ArrayList<Type>(); boolean changed = false; for (Type ti : ct.typeArguments()) { Type ti2 = subst(ti, y, x, Y, X); if (ti2 != ti) changed = true; args.add(ti2); } if (changed) return ct.typeArguments(args); return ct; } } if (t instanceof MacroType) { MacroType mt = (MacroType) t; return subst(mt.definedType(), y, x, Y, X); } return t; } public static Type subst(Type t, XTerm y, XVar x) throws SemanticException { return subst(t, new XTerm[] { y }, new XVar[] { x }); } public static Type subst(Type t, Type Y, ParameterType X) throws SemanticException { return subst(t, new XTerm[] {}, new XVar[] { }, new Type[] { Y }, new ParameterType[] { X }); } public static CConstraint subst(CConstraint t, XTerm y, XVar x) throws SemanticException { return subst(t, new XTerm[] { y }, new XVar[] { x }, new Type[0], new ParameterType[0]); } // FIXME: this is wrong, because types may appear in the constraint public static CConstraint subst(CConstraint t, Type Y, ParameterType X) throws SemanticException { return t; } public static TypeConstraint subst(TypeConstraint t, XTerm y, XVar x) throws SemanticException { if (t == null) return null; return t.subst(y, x); } public static TypeConstraint subst(TypeConstraint t, Type Y, ParameterType X) throws SemanticException { if (t == null) return null; TypeParamSubst subst = new TypeParamSubst((TypeSystem) Y.typeSystem(), Arrays.asList(Y), Arrays.asList(X)); return subst.reinstantiate(t); } public static TypeConstraint subst(TypeConstraint t, XTerm[] y, XVar[] x) throws SemanticException { assert y.length == x.length; if (t == null) return null; for (int i = 0; i < x.length; i++) t = subst(t, y[i], x[i]); return t; } public static TypeConstraint subst(TypeConstraint t, Type[] Y, ParameterType[] X) throws SemanticException { assert Y.length == X.length; if (t == null) return null; for (int i = 0; i < X.length; i++) { if (Y[i] == null) throw new SemanticException("Cannot infer type for parameter " + X[i] + "."); t = subst(t, Y[i], X[i]); } return t; } public static TypeConstraint subst(TypeConstraint t, XTerm[] y, XVar[] x, Type[] Y, ParameterType[] X) throws SemanticException { TypeConstraint t2 = subst(t, y, x); TypeConstraint t3 = subst(t2, Y, X); return t3; } public static CConstraint subst(CConstraint t, XTerm[] y, XVar[] x) throws SemanticException { if (t == null) return null; try { CConstraint c = t.substitute(y, x); return c; } catch (XFailure e) { throw new SemanticException("Cannot instantiate formal parameters on actuals."); } } public static CConstraint subst(CConstraint t, Type[] Y, ParameterType[] X) throws SemanticException { if (t == null) return null; return t; } public static CConstraint subst(CConstraint t, XTerm[] y, XVar[] x, Type[] Y, ParameterType[] X) throws SemanticException { CConstraint t2 = subst(t, y, x); CConstraint t3 = subst(t2, Y, X); return t3; } public static X10FieldInstance subst(X10FieldInstance fi, XTerm[] y, XVar[] x) throws SemanticException { Type ft = subst(fi.type(), y, x); Type rt = subst(fi.rightType(), y, x); ContainerType ct = (ContainerType) subst(fi.container(), y, x); return (X10FieldInstance) fi.type(ft, rt).container(ct); } public static X10FieldInstance subst(X10FieldInstance fi, XTerm y, XVar x) throws SemanticException { return subst(fi, new XTerm[] { y }, new XVar[] { x }); } public static X10LocalInstance subst(X10LocalInstance li, XTerm[] y, XVar[] x) throws SemanticException { Type ft = subst(li.type(), y, x); return li.type(ft); } public static X10LocalInstance subst(X10LocalInstance li, XTerm y, XVar x) throws SemanticException { return subst(li, new XTerm[] { y }, new XVar[] { x }); } /** * @param ci * @param y * @param x * @return * @throws SemanticException */ public static X10ConstructorInstance subst(X10ConstructorInstance ci, XTerm[] y, XVar[] x) throws SemanticException { Type returnType = ci.returnType(); Type newReturnType = subst(returnType, y, x); if (newReturnType != returnType) { ci = ci.returnType(newReturnType); } List<Type> formalTypes = ci.formalTypes(); List<Type> newFormalTypes = subst(formalTypes, y, x); if (newFormalTypes != formalTypes) { ci = ci.formalTypes(newFormalTypes); } List<LocalInstance> newFormalNames = new ArrayList<LocalInstance>(); boolean changed = false; for (LocalInstance li : ci.formalNames()) { try { LocalInstance newLI = subst((X10LocalInstance) li, y, x); if (newLI != li) changed = true; newFormalNames.add(newLI); } catch (SemanticException e) { newFormalNames.add(li); } } if (changed) { ci = (X10ConstructorInstance) ci.formalNames(newFormalNames); } ContainerType ct = (ContainerType) subst(ci.container(), y, x); if (ct != ci.container()) { ci = (X10ConstructorInstance) ci.container(ct); } return ci; } public static X10ConstructorInstance subst(X10ConstructorInstance ci, XTerm y, XVar x) throws SemanticException { return subst(ci, new XTerm[] { y }, new XVar[] { x }); } /** * @param ci * @param y * @param x * @return * @throws SemanticException */ public static MethodInstance subst(MethodInstance mi, XTerm[] y, XVar[] x) throws SemanticException { Type returnType = mi.returnType(); Type newReturnType = subst(returnType, y, x); if (newReturnType != returnType) { mi = mi.returnType(newReturnType); } List<Type> formalTypes = mi.formalTypes(); List<Type> newFormalTypes = subst(formalTypes, y, x); if (newFormalTypes != formalTypes) { mi = mi.formalTypes(newFormalTypes); } List<LocalInstance> newFormalNames = new ArrayList<LocalInstance>(); boolean changed = false; for (LocalInstance li : mi.formalNames()) { try { LocalInstance newLI = subst((X10LocalInstance) li, y, x); if (newLI != li) changed = true; newFormalNames.add(newLI); } catch (SemanticException e) { newFormalNames.add(li); } } if (changed) { mi = (MethodInstance) mi.formalNames(newFormalNames); } ContainerType ct = (ContainerType) subst(mi.container(), y, x); if (ct != mi.container()) { mi = (MethodInstance) mi.container(ct); } return mi; } public static MethodInstance subst(MethodInstance mi, XTerm y, XVar x) throws SemanticException { return subst(mi, new XTerm[] { y }, new XVar[] { x }); } /** * @param ci * @param y * @param x * @return * @throws SemanticException */ public static ClosureInstance subst(ClosureInstance ci, XTerm[] y, XVar[] x) throws SemanticException { Type returnType = ci.returnType(); Type newReturnType = subst(returnType, y, x); if (newReturnType != returnType) { ci = (ClosureInstance) ci.returnType(newReturnType); } List<Type> formalTypes = ci.formalTypes(); List<Type> newFormalTypes = subst(formalTypes, y, x); if (newFormalTypes != formalTypes) { ci = (ClosureInstance) ci.formalTypes(newFormalTypes); } List<LocalInstance> newFormalNames = new ArrayList<LocalInstance>(); boolean changed = false; for (LocalInstance li : ci.formalNames()) { try { LocalInstance newLI = subst((X10LocalInstance) li, y, x); if (newLI != li) changed = true; newFormalNames.add(newLI); } catch (SemanticException e) { newFormalNames.add(li); } } if (changed) { ci = (ClosureInstance) ci.formalNames(newFormalNames); } ClassType ct = (ClassType) subst(ci.typeContainer(), y, x); if (ct != ci.typeContainer()) { ci = (ClosureInstance) ci.typeContainer(ct); } /* FIXME I'm not sure how to do substitution on a ClosureInstance's method container. // It won't matter for the Inlining type transformer which overwrites the method container. // But, it might for other users of the Reinstantiator. // ContainerType ct = (ContainerType) subst(ci.methodContainer(), y, x); if (ct != ci.methodContainer()) { ci = (ClosureInstance) ci.methodContainer(ct); } */ return ci; } public static ClosureInstance subst(ClosureInstance mi, XTerm y, XVar x) throws SemanticException { return subst(mi, new XTerm[] { y }, new XVar[] { x }); } }