boolean allExceptions = true;
for (Expr.PatterMatching.Case pcase : patmat.cases) {
//System.out.println("\thandling " + pcase);
//unify pattern type and inputType
//unify outcome types
TypeScope newScope = env.child();
Type patType = visit(pcase.pattern, newScope, nonGen);
//System.out.println("scope after visiting pattern: " + newScope);
//System.out.println("and patType=" + patType + " for pat " + pcase.pattern);
//System.out.println("***************");
//System.err.println("in " + inputType.getClass());
if (!isException(inputType)) {
unify(patType, inputType);
}
//System.out.println("patType=" + patType + ", inputType=" + inputType);
//System.out.println("$$$$$$$$$$$$$$$$");
Type caseType = null;
for (Instruction instruction : pcase.outcome) {
caseType = analyze(instruction, newScope, nonGen);
}
if (!isException(caseType)) {
unify(caseType, resType);
resType = caseType;
allExceptions = false;
}
//System.out.println("caseType=" + caseType + ", resType=" + resType);
//System.out.println("%%%%%%%%%%%%%%%%%");
}
//System.out.println("resType=" + resType + " for " + patmat);
return allExceptions ? Type.EXCEPTION : resType;
} else if (node instanceof Expr.EThrow) {
Expr.EThrow ethrow = (Expr.EThrow) node;
Type exType = analyze(ethrow.exception, env, nonGen);
unify(exType, Type.EXCEPTION);
return Type.EXCEPTION;
} else if (node instanceof Expr.TryCatch) {
Expr.TryCatch tc = (Expr.TryCatch) node;
Type tryType = null;
for (Instruction instr : tc.tryBody) {
tryType = analyze(instr, env, nonGen);
}
tryType = prune(tryType);
System.err.println("" + tryType.getClass());
System.err.println("TRY TYPE = " + (tryType == Type.EXCEPTION));
Type.Variable resType = new Type.Variable();
if (!isException(tryType)) {
System.err.println("NOOOO");
unify(tryType, resType);
}
for (Expr.PatterMatching.Case pcase : tc.catchCases) {
TypeScope newScope = env.child();
Type patType = visit(pcase.pattern, newScope, nonGen);
unify(patType, Type.EXCEPTION);
Type caseType = null;
for (Instruction instruction : pcase.outcome) {
caseType = analyze(instruction, newScope, nonGen);
}
unify(caseType, resType);
}
return resType;
} else if (node instanceof Expr.ELam) {
Expr.ELam lam = (Expr.ELam) node;
TypeScope newEnv = env.child();
Set<Type> newNonGen = new HashSet<Type>(nonGen);
List<Type> argTypes = new ArrayList<Type>();
for (Named arg : lam.args) {
Type argType = new Type.Variable();
argTypes.add(argType);
newEnv.define(arg.name, argType);
newNonGen.add(argType);
}
Type resultType = null;
for (Instruction instr : lam.instructions) {
resultType = analyze(instr, newEnv, newNonGen);
}
if (lam.type != null) {
unify(resultType, lam.type);
}
return Type.Function(argTypes, resultType);
} else if (node instanceof LetBinding) {
LetBinding let = (LetBinding) node;
TypeScope newEnv = env.child();
Set<Type> newNonGen = new HashSet<Type>(nonGen);
List<Type> argTypes = new ArrayList<Type>();
Type.Variable letTypeVar = new Type.Variable();
//should a function be polymorphic to itself ?
newEnv.define(let.name, letTypeVar);
newNonGen.add(letTypeVar);
for (Named arg : let.args) {
Type argType = new Type.Variable();
argTypes.add(argType);
newEnv.define(arg.name, argType);
newNonGen.add(argType);
}
Type resultType = null;
for (Instruction instr : let.instructions) {
resultType = analyze(instr, newEnv, newNonGen);
}
if (let.type != null) {
unify(resultType, let.type);
}
Type letType = Type.Function(argTypes, resultType);
env.define(let.name, letType);
return letType;
} else if (node instanceof DestructuringLetBinding) {
DestructuringLetBinding let = (DestructuringLetBinding) node;
TypeScope newEnv = env.child();
Set<Type> newNonGen = new HashSet<Type>(nonGen);
List<Type> argTypes = new ArrayList<Type>();
Type letTypeVar = visit(let.main, newEnv, newNonGen);
newNonGen.add(letTypeVar);
for (Pattern arg : let.args) {