// Path: src/chap14/TypeInfo.java
// public static class FunctionType extends TypeInfo {
//     public TypeInfo returnType;
//     public TypeInfo[] parameterTypes;
//     public FunctionType(TypeInfo ret, TypeInfo... params) {
//         returnType = ret;
//         parameterTypes = params;
//     }
//     @Override public boolean isFunctionType() { return true; }
//     @Override public FunctionType toFunctionType() { return this; }
//     @Override public boolean match(TypeInfo obj) {
//         if (!(obj instanceof FunctionType))
//             return false;
//         FunctionType func = (FunctionType)obj;
//         if (parameterTypes.length != func.parameterTypes.length)
//             return false;
//         for (int i = 0; i < parameterTypes.length; i++)
//             if (!parameterTypes[i].match(func.parameterTypes[i]))
//                 return false;
//         return returnType.match(func.returnType);
//     }
//     @Override public String toString() {
//         StringBuilder sb = new StringBuilder();
//         if (parameterTypes.length == 0)
//             sb.append("Unit");
//         else
//             for (int i = 0; i < parameterTypes.length; i++) {
//                 if (i > 0)
//                     sb.append(" * ");
//                 sb.append(parameterTypes[i]);
//             }
//         sb.append(" -> ").append(returnType);
//         return sb.toString();
//     }
// }
// 
// Path: src/chap14/TypeInfo.java
// public static class UnknownType extends TypeInfo {
//     @Override public TypeInfo type() { return ANY; }
//     @Override public String toString() { return type().toString(); }
//     @Override public boolean isUnknownType() { return true; }
//     @Override public UnknownType toUnknownType() { return this; }
// }
// 
// Path: src/chap14/InferTypes.java
// @Reviser public static class UnknownTypeEx extends TypeInfo.UnknownType {
//     protected TypeInfo type = null;
//     public boolean resolved() { return type != null; }
//     public void setType(TypeInfo t) { type = t; }
//     @Override public TypeInfo type() { return type == null ? ANY : type; }
//     @Override public void assertSubtypeOf(TypeInfo t, TypeEnv tenv,
//                                         ASTree where) throws TypeException
//     {
//         if (resolved())
//             type.assertSubtypeOf(t, tenv, where);
//         else
//             ((TypeEnvEx)tenv).addEquation(this, t);
//     }
//     public void assertSupertypeOf(TypeInfo t, TypeEnv tenv, ASTree where)
//         throws TypeException
//     {
//         if (resolved())
//             t.assertSubtypeOf(type, tenv, where);
//         else
//             ((TypeEnvEx)tenv).addEquation(this, t);
//     } 
//     @Override public TypeInfo union(TypeInfo right, TypeEnv tenv) {
//         if (resolved())
//             return type.union(right, tenv);
//         else {
//             ((TypeEnvEx)tenv).addEquation(this, right);
//             return right;
//         }
//     }
//     @Override public TypeInfo plus(TypeInfo right, TypeEnv tenv) {
//         if (resolved())
//             return type.plus(right, tenv);
//         else {
//             ((TypeEnvEx)tenv).addEquation(this, INT);
//             return right.plus(INT, tenv);
//         }
//     }
// }
// 
// Path: src/stone/ast/ASTree.java
// public abstract class ASTree implements Iterable<ASTree> {
//     public abstract ASTree child(int i);
//     public abstract int numChildren();
//     public abstract Iterator<ASTree> children();
//     public abstract String location();
//     public Iterator<ASTree> iterator() { return children(); }
// }


import java.util.List;
import chap14.TypeInfo.FunctionType;
import chap14.TypeInfo.UnknownType;
import chap14.InferTypes.UnknownTypeEx;
import stone.ast.ASTree;
import javassist.gluonj.Require;
import javassist.gluonj.Reviser;
package chap14;

@Require({TypeChecker.class, InferTypes.class})
@Reviser public class InferFuncTypes {
    @Reviser public static class DefStmntEx3 extends TypeChecker.DefStmntEx2 {
        public DefStmntEx3(List<ASTree> c) { super(c); }
        @Override public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
// Path: src/chap14/TypeInfo.java
// public static class FunctionType extends TypeInfo {
//     public TypeInfo returnType;
//     public TypeInfo[] parameterTypes;
//     public FunctionType(TypeInfo ret, TypeInfo... params) {
//         returnType = ret;
//         parameterTypes = params;
//     }
//     @Override public boolean isFunctionType() { return true; }
//     @Override public FunctionType toFunctionType() { return this; }
//     @Override public boolean match(TypeInfo obj) {
//         if (!(obj instanceof FunctionType))
//             return false;
//         FunctionType func = (FunctionType)obj;
//         if (parameterTypes.length != func.parameterTypes.length)
//             return false;
//         for (int i = 0; i < parameterTypes.length; i++)
//             if (!parameterTypes[i].match(func.parameterTypes[i]))
//                 return false;
//         return returnType.match(func.returnType);
//     }
//     @Override public String toString() {
//         StringBuilder sb = new StringBuilder();
//         if (parameterTypes.length == 0)
//             sb.append("Unit");
//         else
//             for (int i = 0; i < parameterTypes.length; i++) {
//                 if (i > 0)
//                     sb.append(" * ");
//                 sb.append(parameterTypes[i]);
//             }
//         sb.append(" -> ").append(returnType);
//         return sb.toString();
//     }
// }
// 
// Path: src/chap14/TypeInfo.java
// public static class UnknownType extends TypeInfo {
//     @Override public TypeInfo type() { return ANY; }
//     @Override public String toString() { return type().toString(); }
//     @Override public boolean isUnknownType() { return true; }
//     @Override public UnknownType toUnknownType() { return this; }
// }
// 
// Path: src/chap14/InferTypes.java
// @Reviser public static class UnknownTypeEx extends TypeInfo.UnknownType {
//     protected TypeInfo type = null;
//     public boolean resolved() { return type != null; }
//     public void setType(TypeInfo t) { type = t; }
//     @Override public TypeInfo type() { return type == null ? ANY : type; }
//     @Override public void assertSubtypeOf(TypeInfo t, TypeEnv tenv,
//                                         ASTree where) throws TypeException
//     {
//         if (resolved())
//             type.assertSubtypeOf(t, tenv, where);
//         else
//             ((TypeEnvEx)tenv).addEquation(this, t);
//     }
//     public void assertSupertypeOf(TypeInfo t, TypeEnv tenv, ASTree where)
//         throws TypeException
//     {
//         if (resolved())
//             t.assertSubtypeOf(type, tenv, where);
//         else
//             ((TypeEnvEx)tenv).addEquation(this, t);
//     } 
//     @Override public TypeInfo union(TypeInfo right, TypeEnv tenv) {
//         if (resolved())
//             return type.union(right, tenv);
//         else {
//             ((TypeEnvEx)tenv).addEquation(this, right);
//             return right;
//         }
//     }
//     @Override public TypeInfo plus(TypeInfo right, TypeEnv tenv) {
//         if (resolved())
//             return type.plus(right, tenv);
//         else {
//             ((TypeEnvEx)tenv).addEquation(this, INT);
//             return right.plus(INT, tenv);
//         }
//     }
// }
// 
// Path: src/stone/ast/ASTree.java
// public abstract class ASTree implements Iterable<ASTree> {
//     public abstract ASTree child(int i);
//     public abstract int numChildren();
//     public abstract Iterator<ASTree> children();
//     public abstract String location();
//     public Iterator<ASTree> iterator() { return children(); }
// }


// Path: src/chap14/InferFuncTypes.java
import java.util.List;
import chap14.TypeInfo.FunctionType;
import chap14.TypeInfo.UnknownType;
import chap14.InferTypes.UnknownTypeEx;
import stone.ast.ASTree;
import javassist.gluonj.Require;
import javassist.gluonj.Reviser;

package chap14;

@Require({TypeChecker.class, InferTypes.class})
@Reviser public class InferFuncTypes {
    @Reviser public static class DefStmntEx3 extends TypeChecker.DefStmntEx2 {
        public DefStmntEx3(List<ASTree> c) { super(c); }
        @Override public TypeInfo typeCheck(TypeEnv tenv) throws TypeException {
            FunctionType func = super.typeCheck(tenv).toFunctionType();