/*
* 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.constraints;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import polyglot.util.Copy;
import polyglot.util.InternalCompilerError;
import x10.constraint.XFailure;
import x10.constraint.XTerm;
import x10.constraint.XVar;
import x10.types.ConstrainedType;
import x10.types.MacroType;
import x10.types.ParameterType;
import x10.types.X10ClassDef;
import x10.types.X10ClassType;
import polyglot.types.Context;
import x10.types.FunctionType;
import x10.types.X10ProcedureDef;
import x10.types.X10ProcedureInstance;
import x10.types.TypeParamSubst;
import polyglot.types.TypeSystem;
import x10.types.ParameterType.Variance;
import x10.types.matcher.Subst;
import polyglot.types.Name;
import polyglot.types.JavaPrimitiveType;
import polyglot.types.SemanticException;
import polyglot.types.Type;
import polyglot.types.Types;
/**
* A TypeConstraint is a conjunction of constraints of the form T1 <: T2, or T1 == T2,
* or T haszero.
*
* Todo: This needs to be fixed. The constraints in this have to be used to figure
* out whether c is entailed. This needs a proper constraint representation, e.g.
* X <: Y, Y <: Z |- X <: Z
*
* @author njnystrom
* @author vj
*
*/
public class TypeConstraint implements Copy, Serializable {
private static final long serialVersionUID = -6305620393028945867L;
List<SubtypeConstraint> terms;
public TypeConstraint() {terms = new ArrayList<SubtypeConstraint>();}
/**
* Modifies "this" to match the unification of the two types.
* Returns true if the two types are unifiable.
* @param t1
* @param t2
* @return
*/
public boolean unify(Type t1, Type t2, TypeSystem xts) {
final Context emptyContext = (Context) t1.typeSystem().emptyContext();
t1 = Types.stripConstraints(t1);
t2 = Types.stripConstraints(t2);
if (xts.typeEquals(t1, t2, emptyContext /*dummy*/)) return true;
if ((t1 instanceof ParameterType) || (t2 instanceof ParameterType)) {
addTerm(new SubtypeConstraint(t1, t2, SubtypeConstraint.Kind.EQUAL));
if (! (consistent(emptyContext))) return false;
}
if ((t1 instanceof X10ClassType) && (t2 instanceof X10ClassType)) {
X10ClassType xt1 = (X10ClassType) t1;
X10ClassType xt2 = (X10ClassType) t2;
Type bt1 = xt1.x10Def().asType();
Type bt2 = xt2.x10Def().asType();
if (!xts.typeEquals(bt1,bt2, emptyContext)) return false;
List<Type> args1 = xt1.typeArguments();
List<Type> args2 = xt2.typeArguments();
if (args1 == null && args2 == null) return true;
if (args1 == null || args2 == null) return false;
if (args1.size() != args2.size()) return false;
for (int i=0; i < args1.size(); ++i) {
Type p1 = args1.get(i);
Type p2 = args2.get(i);
boolean res = unify(p1,p2,xts);
if (!res) return false;
}
}
return true;
}
public List<SubtypeConstraint> terms() {return terms;}
public TypeConstraint copy() {
try {
final TypeConstraint res = (TypeConstraint) super.clone();
res.terms = new ArrayList<SubtypeConstraint>(terms);
return res;
}
catch (CloneNotSupportedException e) {
assert false;
return this;
}
}
public TypeConstraint addIn(TypeConstraint c) {
terms.addAll(c.terms());
return this;
}
public void addTerm(SubtypeConstraint c) {terms.add(c);}
public void addTerms(Collection<SubtypeConstraint> terms) {this.terms.addAll(terms);}
public boolean entails(TypeConstraint c, Context context) {
Context xc = context.pushBlock();
xc.setTypeConstraintWithContextTerms(this);
return c.consistent(xc);
}
public boolean consistent(Context context) {
TypeSystem ts = context.typeSystem();
for (SubtypeConstraint t : terms()) {
if (t.isEqualityConstraint()) {
if (! ts.typeEquals(t.subtype(), t.supertype(), context)) return false;
} else if (t.isSubtypeConstraint()) {
if (! ts.isSubtype(t.subtype(), t.supertype(), context)) return false;
} else if (t.isHaszero()) {
if (!Types.isHaszero(t.subtype(),context)) return false;
} else if (t.isIsRef()) {
if (!Types.isIsRef(t.subtype(),context)) return false;
}
}
return true;
}
/*
* (non-Javadoc)
*
* @see x10.types.TypeConstraint#subst(x10.constraint.XTerm,
* x10.constraint.XVar, boolean)
*/
public TypeConstraint subst(XTerm y, XVar x) {
TypeConstraint c = new TypeConstraint();
List<SubtypeConstraint> l = c.terms;
for (SubtypeConstraint s : terms) l.add(s.subst(y, x));
return c;
}
@Override public String toString() {return terms.toString();}
public void checkTypeQuery( TypeConstraint query, XVar ythis, XVar xthis, XVar[] y, XVar[] x,
Context context) throws SemanticException {
if (! consistent(context)) throw new SemanticException("Call invalid; type environment is inconsistent.");
if (query != null) {
if ( ! ((TypeSystem) context.typeSystem()).consistent(query, context)) {
throw new SemanticException("Type guard " + query + " cannot be established; inconsistent in calling context.");
}
TypeConstraint query2 = xthis==null ? query : query.subst(ythis, xthis);
for (int i = 0; i < y.length; i++) query2 = query2.subst(y[i], x[i]);
if (! entails(query2, context))
throw new SemanticException("Call invalid; calling environment does not entail the method guard.");
}
}
public static <PI extends X10ProcedureInstance<?>> Type[] inferTypeArguments(PI me,
Type thisType, List<Type> actuals, List<Type> formals,
List<Type> typeFormals, Context context) throws SemanticException {
TypeSystem xts = (TypeSystem) me.typeSystem();
TypeConstraint tenv = new TypeConstraint();
CConstraint env = ConstraintManager.getConstraintSystem().makeCConstraint();
XVar ythis = thisType instanceof ConstrainedType ? Types.selfVar((ConstrainedType) thisType) : null;
if (ythis == null) {
CConstraint c = Types.xclause(thisType);
c = (c == null) ? ConstraintManager.getConstraintSystem().makeCConstraint() : c.copy();
ythis = ConstraintManager.getConstraintSystem().makeUQV();
c.addSelfBinding(ythis);
c.setThisVar(ythis);
thisType = Types.xclause(Types.baseType(thisType), c);
}
assert actuals.size() == formals.size();
ParameterType[] X = new ParameterType[typeFormals.size()];
Type[] Y = new Type[typeFormals.size()];
Type[] Z = new Type[typeFormals.size()];
XVar[] x = new XVar[formals.size()];
XVar[] y = new XVar[formals.size()];
for (int i = 0; i < typeFormals.size(); i++) {
Type xtype = typeFormals.get(i);
xtype = xts.expandMacros(xtype);
Type ytype = new ParameterType(xts, me.position(), me.position(), Name.makeFresh(), Types.ref((X10ProcedureDef) me.def()));
// TODO: should enforce this statically
if (! (xtype instanceof ParameterType))
assert xtype instanceof ParameterType : xtype + " is not a ParameterType, is a " + (xtype != null ? xtype.getClass().getName() : "null");
tenv.addTerm(new SubtypeConstraint(xtype, ytype, true));
X[i] = (ParameterType) xtype;
Y[i] = ytype;
Z[i] = ytype;
}
for (int i = 0; i < formals.size(); i++) {
Type xtype = formals.get(i);
Type ytype = actuals.get(i);
xtype = xts.expandMacros(xtype);
ytype = xts.expandMacros(ytype);
// Be sure to copy the constraints since we use the self vars
// in other constraints and don't want to conflate them if
// realX returns the same constraint twice.
final CConstraint yc = Types.realX(ytype).copy();
XVar yi = Types.selfVar(yc);
if (yi == null) {
// This must mean that yi was not final, hence it cannot occur in
// the dependent clauses of downstream yi's.
yi = ConstraintManager.getConstraintSystem().makeUQV(); // xts.xtypeTranslator().genEQV(ytype, false);
}
tenv.addTypeParameterBindings(xtype, ytype, false);
// CConstraint xc = X10TypeMixin.realX(xtype).copy();
XVar xi = xts.xtypeTranslator().translate(me.formalNames().get(i));
x[i] = xi;
y[i] = yi;
}
// We'll subst selfVar for THIS.
XVar xthis = null;
if (me.def() instanceof X10ProcedureDef) xthis = (XVar) ((X10ProcedureDef) me.def()).thisVar();
if (xthis == null) xthis = ConstraintManager.getConstraintSystem().makeThis();
try {expandTypeConstraints(tenv, context);
} catch (XFailure f) {}
// Create a big query for inferring type parameters.
// LIMITATION: can only infer types when actuals are subtypes of formals.
// This updates Y with new actual type arguments.
inferTypeArguments(context, me, tenv, X, Y, Z, x, y, ythis, xthis);
for (int i = 0; i < Z.length; i++)
if (Y[i] == Z[i])
throw new SemanticException("Cannot infer type for type parameter " + X[i] + ".", me.position());
return Y;
}
/**
* Infer the type constraints to add from this, given <code>ytype <: xtype</code>.
* The type constraints to be added are of the form given below, where
* <code>X</code> is a type parameter:
* <ul>
* <li> <code>Type <: X</code>
* <li> <code>X <: Type</code>
* <li> <code>Type == X</code>
* The algorithm proceeds as follows. From each formal type <code>xtype</code> and
* corresponding actual type <code>ytype</code>, we generate a set of type constraints thus:
*
* <ul>
* <li> Replace <code>xtype</code> with <code> baseType(xtype)</code>. It is legitimate to strip the constraint,
* because the type constraint <code>S <: X{c}</code> or <code>S == X{c}</code> can be solved by
* either <code>X==S</code> or <code>X==S{c}</code>. We choose to solve it with <code>S</code>.
* <li> Do nothing and return if <code>xtype</code> is <code>null</code>.
* <li>If <code>xtype</code> is a class type, we call the helper <code>addTypeParameterBindings
* (X10ClassType xtype, Type ytype, boolean isEqual)</code>. This will case on <code>ytype</code>.
* <li> If <code>xtype</code> is a <code>ParameterType</code>, <code>X</code>, then generate the
* constraint <code>ytype <: X </code> (if <code>isEqual</code>), else <code>ytype == X</code>.
* </ul>
* <p>
* @param xtype -- the formal type
* @param ytype -- the actual type
* @throws XFailure
*/
void addTypeParameterBindings(Type xtype, Type ytype, boolean isEqual) {
xtype = Types.baseType(xtype);
if (xtype == null) return;
if (xtype instanceof ParameterType) {
// do not strip constraints from ytype
addTerm(new SubtypeConstraint(ytype, xtype, isEqual));
return;
}
if (xtype instanceof FunctionType) {
addTypeParameterBindings((FunctionType) xtype, ytype, isEqual);
return;
}
if (xtype instanceof X10ClassType) {
addTypeParameterBindings((X10ClassType) xtype, ytype, isEqual);
return;
}
}
/**
* This method is called only by <code>addTypeParameterBindings(xtype: Type, ytype: Type, boolean)</code>, once
* xtype is determined to be an <code>X10ClassType</code>. Replace <code>ytype</code> with
* <code>baseType(ytype)</code>. The constraint <code>{c}</code> can be ignored because we are trying
* to generate type constraints from <code>S{c} <: XClass</code>, and <code>{c}</code> does not play a role.
* The only type constraints that will be generated will involve type-parameters occurring inside parameters of
* <code>XClass</code>.
* <p>
* This leaves <code>xtype</code> and <code>ytype</code> as class types. Now compare the corresponding definitions.
* If they are the same then determine if the types have parameters. Recursively generate constraints from the
* corresponding pairs of parameters, depending on whether that position is invariant, covariant or contravariant.
*
* <p> Otherwise (the definitions are not the same), repeat the process, replacing <code>ytype</code> successively
* with its super type and with the interfaces it implements.
*
* @param xtype -- The formal type (may contain type parameters).
* @param ytype
* @param isEqual
* @throws XFailure
*/
private void addTypeParameterBindings(X10ClassType xtype, Type ytype, boolean isEqual) {
ytype = Types.baseType(ytype);
if (ytype == null)
return;
if (ytype instanceof X10ClassType) {
X10ClassDef xcd = xtype.x10Def();
X10ClassType yct = (X10ClassType) ytype;
X10ClassDef ycd = yct.x10Def();
if (ycd == xcd) {
// Now we are in the case xct is Foo[S1,..,Sn] and ytype is Foo[T1,...,Tn]
// This will generate for each i, Si <: Ti, Si == Ti or Ti <: Si depending on
// whether the i'th argument is contravariant, invariant or covariant.
if (xtype.typeArguments() != null && yct.typeArguments() != null) {
for (int i = 0; i < yct.typeArguments().size(); i++) {
Type xt = xtype.typeArguments().get(i);
Type yt = yct.typeArguments().get(i);
ParameterType.Variance v = xcd.variances().get(i);
switch (v) {
case INVARIANT: {addTypeParameterBindings(xt, yt, true);break;}
case CONTRAVARIANT:{addTypeParameterBindings(yt, xt, false);break;}
case COVARIANT: {addTypeParameterBindings(xt, yt, false);break;}
}
}
}
}
else {
addTypeParameterBindings(xtype, yct.superClass(), isEqual);
for (Type t: yct.interfaces()) addTypeParameterBindings(xtype, t, isEqual);
}
}
if (ytype instanceof ParameterType) { // can happen because of contravariance
addTerm(new SubtypeConstraint(xtype, ytype, isEqual));
}
}
/**
* This method is called only by <code>addTypeParameterBindings(xtype: Type, ytype: Type, boolean)</code>, once
* xtype is determined to be a <code>FunctionType</code>. Replace <code>ytype</code> with
* <code>baseType(ytype)</code>. The constraint <code>{c}</code> can be ignored because we are trying
* to generate type constraints from <code>((T1,...,Tn){h}=>T){c} <: (S1,...,Sn){g}=>S</code>, and <code>{c}</code>
* does not play a role.
* The only type constraints that will be generated will involve type-parameters occurring inside parameters of
* <code>XClass</code>.
* <p>
* Check that <code>ytype</code> is a function type.
* This leaves <code>xtype</code> and <code>ytype</code> as function types. Now compare the numbers of arguments.
* If they are the same, the return types are either both void or both non-void, and the subtype's guard entails
* the supertype's, then proceed to look at the formal types.
* Recursively generate constraints from the corresponding pairs of argument types, in a contravariant fashion,
* and from the return types, in a covariant fashion (unless they are void).
* <p>
* Otherwise (ytype is not a function type), repeat the process, replacing <code>ytype</code> successively
* with its super type and with the interfaces it implements.
*
* @param xft -- The formal function type (may contain type parameters).
* @param ytype
* @param isEqual
* @throws XFailure
*/
private void addTypeParameterBindings(FunctionType xft, Type ytype, boolean isEqual) {
ytype = Types.baseType(ytype);
if (ytype == null)
return;
if (ytype instanceof FunctionType) {
// The arguments may be named, and these names may occur
// in arg types, guard, return types. These names must
// be normalized. See FunctionType_c.equalImpl.
FunctionType yft = (FunctionType) ytype;
TypeSystem ts = yft.typeSystem();
List<Type> Tl = yft.argumentTypes();
Type T = yft.returnType();
CConstraint h = yft.guard();
List<Type> Sl = xft.argumentTypes();
Type S = xft.returnType();
CConstraint g = xft.guard();
if ( Tl.size() == Sl.size() && (T.isVoid() == S.isVoid())) {
XVar[] ys = Types.toVarArray(Types.toLocalDefList(yft.formalNames()));
XVar[] xs = Types.toVarArray(Types.toLocalDefList(xft.formalNames()));
if (g != null) {
try {g = g.substitute(xs, ys);
} catch (XFailure e) {
throw new InternalCompilerError("Unexpected exception comparing function types", xft.position(), e);
}
}
if (h != null) {
try {h = h.substitute(xs, ys);
} catch (XFailure e) {
throw new InternalCompilerError("Unexpected exception comparing function types", yft.position(), e);
}
}
if (ts.env(ts.emptyContext()).entails(h, g)) {
// Now we are in the case xft is (S1,..,Sn){g}=>S and yft is (T1,...,Tn){h}=>T
// This will generate for each i, Si <: Ti (contravariant arguments) and
// T <: S (covariant return types).
for (int i = 0; i < Sl.size(); i++) {
Type Si = Sl.get(i);
Type Ti = Tl.get(i);
try {
Ti = Subst.subst(Ti, xs, ys, new Type[]{}, new ParameterType[]{});
Si = Subst.subst(Si, xs, ys, new Type[]{}, new ParameterType[]{});
} catch (SemanticException e) {
throw new InternalCompilerError("Unexpected exception comparing function types", e);
}
addTypeParameterBindings(Ti, Si, false);
}
if (!S.isVoid()) {
try {
T = Subst.subst(T, xs, ys, new Type[]{}, new ParameterType[]{});
S = Subst.subst(S, xs, ys, new Type[]{}, new ParameterType[]{});
} catch (SemanticException e) {
throw new InternalCompilerError("Unexpected exception comparing function types", e);
}
addTypeParameterBindings(S, T, false);
}
}
}
}
else if (ytype instanceof X10ClassType) {
X10ClassType yct = (X10ClassType) ytype;
addTypeParameterBindings(xft, yct.superClass(), isEqual);
for (Type t: yct.interfaces()) {
addTypeParameterBindings(xft, t, isEqual);
}
}
if (ytype instanceof ParameterType) { // can happen because of contravariance
addTerm(new SubtypeConstraint(xft, ytype, isEqual));
}
}
private static void expandTypeConstraints(TypeConstraint tenv, Context context) throws XFailure {
List<SubtypeConstraint> originalTerms = new ArrayList<SubtypeConstraint>(tenv.terms());
for (SubtypeConstraint term : originalTerms) expandTypeConstraints(tenv, term, context);
}
/**
* Expand generic constraints in the type environment.
* If we have a constraint on two generic types, <code>A[X]</code> and <code>B[Y]</code>,
* also add the appropriate constraint on the parameter types <code>X</code> and <code>Y</code>.
* Here are the possibilities:
* <table border="1"><tr><td valign="top">
* 1. A[X] == A[Y] </td><td colspan="2"> X==Y </td></tr><tr><td valign="top">
* 2. A[X] == B[Y] </td><td colspan="2"> not consistent </td></tr><tr><td rowspan="3" valign="top">
* 3. A[X] <: A[Y] </td><td> A[ T] (invariant)? </td><td> X==Y </td></tr><tr><td>
* A[+T] (covariant)? </td><td> X<:Y </td></tr><tr><td>
* A[-T] (contravariant)? </td><td> X:>Y </td></tr><tr><td rowspan="10" valign="top">
* 4. A[X] <: B[Y] </td><td> A[ T] <: B[ T] </td><td> X==Y </td></tr><tr><td>
* A[+T] <: B[ T] </td><td> X<:Y </td></tr><tr><td>
* A[-T] <: B[ T] </td><td> X:>Y </td></tr><tr><td>
* A[ T] <: B[+T] </td><td> X<:Y </td></tr><tr><td>
* A[+T] <: B[+T] </td><td> X<:Y </td></tr><tr><td>
* A[-T] <: B[+T] </td><td> no constraint on X and Y </td></tr><tr><td>
* A[ T] <: B[-T] </td><td> X:>Y </td></tr><tr><td>
* A[+T] <: B[-T] </td><td> no constraint on X and Y </td></tr><tr><td>
* A[-T] <: B[-T] </td><td> X:>Y </td></tr><tr><td>
* A[T] <: B[S] && T??S </td><td> X??Y (instantiate constraint on T and S) </td></tr><tr><td>
* 5. exists Q s.t. A <: Q[X] <: B[Y] </td><td colspan="2"> ??? </td>
* </tr></table>
* FIXME: Only the equality case (1) and the same type case (3) are handled for now. Also "haszero" is not expanded.
*/
private static void expandTypeConstraints(TypeConstraint tenv, SubtypeConstraint term, Context context) throws XFailure {
if (term.isHaszero() || term.isIsRef()) return;
TypeSystem xts = (TypeSystem) context.typeSystem();
Type b = xts.expandMacros(term.subtype());
Type p = xts.expandMacros(term.supertype());
if (!b.isClass() || !p.isClass()) return;
X10ClassType sub = (X10ClassType) b.toClass();
X10ClassType sup = (X10ClassType) p.toClass();
List<Type> subTypeArgs = sub.typeArguments();
List<Type> supTypeArgs = sup.typeArguments();
if (term.isEqualityConstraint()) {
X10ClassDef def = sub.x10Def();
if (def != sup.x10Def()) return; // skip case 2
if (subTypeArgs == null || supTypeArgs == null) return;
if (subTypeArgs.isEmpty() || subTypeArgs.size() != supTypeArgs.size()) return;
for (int i = 0; i < subTypeArgs.size(); i++) {
Type ba = subTypeArgs.get(i);
Type pa = supTypeArgs.get(i);
if (xts.typeEquals(ba, pa, context)) continue;
SubtypeConstraint eq = new SubtypeConstraint(ba, pa, true);
tenv.addTerm(eq);
expandTypeConstraints(tenv, eq, context);
}
}
else {
assert term.isSubtypeConstraint();
X10ClassDef def = sub.x10Def();
if (def != sup.x10Def()) return; // FIXME: skip cases 4 and 5
if (subTypeArgs == null || supTypeArgs == null) return;
if (subTypeArgs.isEmpty() || subTypeArgs.size() != supTypeArgs.size()) return;
List<Variance> variances = def.variances();
for (int i = 0; i < subTypeArgs.size(); i++) {
Type ba = subTypeArgs.get(i);
Type pa = supTypeArgs.get(i);
if (xts.typeEquals(ba, pa, context)) continue;
SubtypeConstraint eq = null;
switch (variances.get(i)) {
case INVARIANT:
eq = new SubtypeConstraint(ba, pa, true);
break;
case COVARIANT:
eq = new SubtypeConstraint(ba, pa, false);
break;
case CONTRAVARIANT:
eq = new SubtypeConstraint(pa, ba, false);
break;
}
tenv.addTerm(eq);
expandTypeConstraints(tenv, eq, context);
}
}
}
/**
* Return in Y the result of inferring types for arguments to the call me.
* @param <PI>
* @param context -- The context in which this call is being made
* @param me -- the PI against which this call is being made
* @param tenv -- The type environment generated from this call (contains actualType <: formalType for each i)
* @param X -- The list of types of the formals in me
* @param Y -- The value of Y[i] is changed only if a type can be inferred
* @param Z -- A copy of the input Y.
* @param x -- formals for me
* @param y -- names of actual arguments to the call
* @param ythis -- name of the receiver in the calling environment
* @param xthis -- formal name of the receiver
* @throws SemanticException
*/
private static <PI extends X10ProcedureInstance<?>> void inferTypeArguments(Context context, PI me, TypeConstraint tenv,
ParameterType[] X, Type[] Y, Type[] Z, XVar[] x, XVar[] y, XVar ythis, XVar xthis) throws SemanticException
{
TypeSystem xts = (TypeSystem) me.typeSystem();
Outer: for (int i = 0; i < Y.length; i++) {
Type Yi = Y[i];
List<Type> equal = new ArrayList<Type>();
List<Type> upper = new ArrayList<Type>();
List<Type> lower = new ArrayList<Type>();
List<Type> worklist = new ArrayList<Type>();
worklist.add(Yi);
for (int j = 0; j < worklist.size(); j++) {
Type m = worklist.get(j);
for (SubtypeConstraint term : tenv.terms()) {
SubtypeConstraint eq = term;
if (term.isHaszero() || term.isIsRef())continue; // haszero constraints do not participate in type inference
Type sub = eq.subtype();
Type sup = eq.supertype();
if (term.isEqualityConstraint()) {
if (m.typeEquals(sub, context)) {
if (! equal.contains(sup)) equal.add(sup);
if (! worklist.contains(sup)) worklist.add(sup);
}
if (m.typeEquals(sup, context)) {
if (!equal.contains(sub)) equal.add(sub);
if (!worklist.contains(sub)) worklist.add(sub);
}
}
else {
assert term.isSubtypeConstraint();
if (m.typeEquals(sub, context)) {
if (!upper.contains(sup)) upper.add(sup);
if (!worklist.contains(sup)) worklist.add(sup);
}
if (m.typeEquals(sup, context)) {
if (!lower.contains(sub)) lower.add(sub);
if (!worklist.contains(sub)) worklist.add(sub);
}
}
}
}
for (Type Xi : X) {
upper.remove(Xi);
lower.remove(Xi);
equal.remove(Xi);
}
for (Type Zi : Z) {
upper.remove(Zi);
lower.remove(Zi);
equal.remove(Zi);
}
Type equalBound = null;
TypeSystem ts = context.typeSystem();
for (Type t : equal) {
boolean valid = true;
for (Type s : equal) {
if (! ts.typeEquals(t,s, context)) {
valid = false;
break;
}
}
if (valid)
for (Type u : upper) {
if (! ts.isSubtype(t, u, context)) {
valid = false;
break;
}
}
if (valid)
for (Type l : lower) {
if (! ts.isSubtype(l,t, context)) {
valid = false;
break;
}
}
if (valid) Y[i] = t;
continue Outer; // We have found a solution for Y[i]
}
Type upperBound = null;
for (Type t : upper)
if (t != null) upperBound = (upperBound==null)?t:Types.meetTypes(xts, upperBound, t, context);
if (upperBound != null) {
boolean valid = true;
for (Type l : lower) {
if (! ts.isSubtype(l,upperBound, context)) {
valid = false;
break;
}
}
if (valid) Y[i] = upperBound;
continue;
}
Type lowerBound = null;
for (Type t : lower) if (t != null)
lowerBound = (lowerBound==null)? t : xts.leastCommonAncestor(lowerBound, t, context);
if (lowerBound != null) Y[i] = lowerBound;
//System.err.println("(Diagnostic) No constraint on type parameters. " +
// "Returning Any instead of throwing an exception."
// + (X[i] != null ? "\n\t: Position: " + X[i].position().toString() : ""));
//Y[i] = xts.Any();
//throw new SemanticException("Could not infer type for type parameter " + X[i] + ".", me.position());
}
}
}