public SubstMap unify(final Loc loc, final Type other, final TypeEnv env) { if (env.checkVisited(this, other)) return SubstMap.EMPTY; if (other instanceof TypeVar) return SubstMap.bindVar(loc, (TypeVar) other, this); // if our application expression can be evaluated, unify against that. if (isAbsApply()) return eval().unify(loc, other, env); final Type otherEval = other.deref().eval(); if (otherEval instanceof TypeApp) { final TypeApp otherApp = (TypeApp) otherEval; final SubstMap baseSubst = base.unify(loc, otherApp.base, env); if (baseSubst != null) { final SubstMap argSubst = arg.subst(baseSubst).unify(loc, otherApp.arg.subst(baseSubst), env); if (argSubst != null) return baseSubst.compose(loc, argSubst); } } else if (kind.equals(otherEval.getKind())) { // other is not an application expression, but kinds match. // other type classes do opportunistic matching of type apps // implementations of unify. This approach is really ad-hoc, // needs to be rationalized. return otherEval.unify(loc, this, env); } return null; }
public Type eval() { if (reduced != null) return reduced; if (inEval) return this; final Type baseEval = base.deref().eval(); final Type argEval = arg.deref().eval(); if (!(baseEval instanceof TypeCons)) // error has been raised return this; final TypeCons cons = (TypeCons) baseEval; final Type body = cons.getBody(); if (body == null) return reduced(baseEval, argEval); // check base abs param kind against arg kind if (!checkKindAgreement(cons, argEval)) // error has been raised return this; // evaluate by building param->arg subst map and // applying it to body term final SubstMap argMap = new SubstMap(); final Collection<TypeParam> params = body.getParams().values(); if (params.size() == 1) { final TypeParam param = params.iterator().next(); assert param.getTypeScope() == body : "nope"; argMap.put(param, argEval); } else { if (!(argEval instanceof TypeTuple)) assert false; final Iterator<Type> argList = ((TypeTuple) argEval).getMembers().iterator(); for (final TypeParam param : params) { assert param.getTypeScope() == body : "nope"; argMap.put(param, argList.next()); } } final Type bodySubst = new TypeApplier(body, argMap).apply(); // evaluate body with args substituted for params inEval = true; reduced = bodySubst.eval(); inEval = false; if (Session.isDebug()) Session.debug( body.getLoc(), "eval {0}({1}) => {2}", body.dump(), argMap.dump(), reduced.dump()); return reduced; }