Show
Ignore:
Timestamp:
10/29/09 14:22:34 (4 weeks ago)
Author:
dr2chase
Message:

Looks like a fix for the interpreter; cleanup of compiler phase structure; minor (and insufficient) sanitization of overloaded names

Location:
trunk/ProjectFortress/src/com/sun/fortress
Files:
1 added
25 modified

Legend:

Unmodified
Added
Removed
  • trunk/ProjectFortress/src/com/sun/fortress/Shell.java

    r4191 r4296  
    4040import com.sun.fortress.compiler.Parser; 
    4141import com.sun.fortress.compiler.index.ComponentIndex; 
     42import com.sun.fortress.compiler.phases.Phase; 
    4243import com.sun.fortress.compiler.phases.PhaseOrder; 
    4344import com.sun.fortress.nodes.Api; 
     
    7576 
    7677    /* set this statically if you only want to run up to a certain phase */ 
    77     private static PhaseOrder finalPhase = PhaseOrder.ENVGEN; 
     78    private static PhaseOrder[] finalPhaseOrder = null; 
    7879 
    7980    private static final String defaultRepositoryDir = ProjectProperties.ANALYZED_CACHE_DIR; 
     
    9192        return _repository; 
    9293    } 
    93  
    94     public static void setPhase( PhaseOrder phase ){ 
    95         finalPhase = phase; 
     94    
     95    public static void setPhaseOrder( PhaseOrder[] order ){ 
     96        finalPhaseOrder = order; 
    9697    } 
    9798 
     
    371372                useCompilerLibraries(); 
    372373                setTypeChecking(true); 
    373                 setPhase( PhaseOrder.CODEGEN ); 
     374                setPhaseOrder( PhaseOrder.compilerPhaseOrder ); 
    374375                return_code = compilerPhases(args, Option.<String>none(), what); 
    375376            } else if (what.equals("junit")) { 
     
    378379                useCompilerLibraries(); 
    379380                setTypeChecking(true); 
    380                 setPhase( PhaseOrder.CODEGEN ); 
     381                setPhaseOrder( PhaseOrder.compilerPhaseOrder ); 
    381382                return_code = link(args); 
    382383            } else if (what.equals("build")) { 
    383384                useCompilerLibraries(); 
    384385                setTypeChecking(true); 
    385                 setPhase( PhaseOrder.CODEGEN ); 
     386                setPhaseOrder( PhaseOrder.compilerPhaseOrder ); 
    386387                return_code = link(args); 
    387388            } else if (what.equals("walk")) { 
    388389                useFortressLibraries(); 
    389390                setScala(false); 
    390                 setPhase( PhaseOrder.ENVGEN ); 
     391                setPhaseOrder( PhaseOrder.interpreterPhaseOrder ); 
    391392                walk(args); 
    392393            } else if ( what.equals("api" ) ){ 
     
    404405            } else if ( what.equals( "disambiguate" ) ){ 
    405406                useCompilerLibraries(); 
    406                 setPhase( PhaseOrder.DISAMBIGUATE ); 
     407                setPhaseOrder( PhaseOrder.disambiguatePhaseOrder ); 
    407408                return_code = compilerPhases(args, Option.<String>none(), what); 
    408409            } else if ( what.equals( "desugar" ) ){ 
     
    410411                setTypeChecking(true); 
    411412                setObjExprDesugaring(true); 
    412                 setPhase( PhaseOrder.DESUGAR ); 
     413                setPhaseOrder( PhaseOrder.desugarPhaseOrder ); 
     414 
    413415                return_code = compilerPhases(args, Option.<String>none(), what); 
    414416            } else if ( what.equals( "grammar" ) ){ 
    415417                useCompilerLibraries(); 
    416                 setPhase( PhaseOrder.GRAMMAR ); 
     418                setPhaseOrder( PhaseOrder.grammarPhaseOrder ); 
     419 
    417420                return_code = compilerPhases(args, Option.<String>none(), what); 
    418421            } else if (what.equals("typecheck")) { 
    419422                useCompilerLibraries(); 
    420423                setTypeChecking(true); 
    421                 setPhase( PhaseOrder.TYPECHECK ); 
     424                setPhaseOrder( PhaseOrder.typecheckPhaseOrder ); 
     425 
    422426                return_code = compilerPhases(args, Option.<String>none(), what); 
    423427            } else if (what.equals("test-coercion")) { 
    424428                useCompilerLibraries(); 
    425429                setTypeChecking(true); 
    426                 setPhase(PhaseOrder.TYPECHECK); 
     430                setPhaseOrder( PhaseOrder.typecheckPhaseOrder ); 
     431 
    427432                return_code = compilerPhases(args, Option.<String>none(), what); 
    428433            } else if (what.equals("typecheck-old")) { 
     
    430435                /* TODO: remove the next line once type checking is permanently turned on */ 
    431436                setTypeChecking(true); 
    432                 setPhase( PhaseOrder.TYPECHECK ); 
     437                setPhaseOrder( PhaseOrder.typecheckPhaseOrder ); 
     438 
    433439                return_code = compilerPhases(args, Option.<String>none(), what); 
    434440            } else if (what.equals("test")) { 
    435441                useCompilerLibraries(); 
    436                 setPhase( PhaseOrder.ENVGEN ); 
     442                setPhaseOrder( PhaseOrder.interpreterPhaseOrder ); 
    437443                walkTests(args, false); 
    438444            } else if (what.contains(ProjectProperties.COMP_SOURCE_SUFFIX) 
     
    440446                useFortressLibraries(); 
    441447                setScala(false); 
    442                 setPhase( PhaseOrder.ENVGEN ); 
     448                setPhaseOrder( PhaseOrder.interpreterPhaseOrder ); 
    443449                walk(Arrays.asList(tokens)); 
    444450            } else if (what.equals("help")) { 
     
    565571    public static FValue eval( String file, List<String> args, boolean unCacheWhenDone ) 
    566572        throws Throwable { 
    567         setPhase( PhaseOrder.ENVGEN ); 
     573        setPhaseOrder( PhaseOrder.interpreterPhaseOrder ); 
    568574        if ( ! isComponent(file) ) 
    569575            throw new UserError(file + " is not a component file."); 
     
    12121218                                        Iterable<Component> components, 
    12131219                                        final long lastModified) throws StaticError { 
    1214         AnalyzeResult result = finalPhase.makePhase(repository,env,apis,components,lastModified).run(); 
     1220        Phase ph =  
     1221            PhaseOrder.makePhaseOrder(finalPhaseOrder, repository, env, apis, components, lastModified); 
     1222        AnalyzeResult result = ph.run(); 
    12151223        return result; 
    12161224    } 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/OverloadRewriteVisitor.java

    r4291 r4296  
    8989    public final static Comparator<List<? extends Overloading>> overloadListComparator = new AnyListComparer<Overloading>(overloadComparator); 
    9090 
     91     
     92     
    9193    final private Map<List<? extends Overloading>, TypedIdOrOpList> overloadedFunctions = new BATree<List<? extends Overloading>, TypedIdOrOpList>(overloadListComparator); 
    9294    final private Map<List<? extends Overloading>, TypedIdOrOpList> overloadedOperators = new BATree<List<? extends Overloading>, TypedIdOrOpList>(overloadListComparator); 
     95 
     96    final private boolean forInterpreter; 
     97 
     98    public OverloadRewriteVisitor(boolean forInterpreter) { 
     99        this.forInterpreter = forInterpreter; 
     100    } 
     101 
    93102 
    94103    @Override 
    95104    public Node forFnRefOnly(FnRef that, ExprInfo info, 
    96105                             List<StaticArg> staticArgs, IdOrOp originalName, List<IdOrOp> fns, 
    97                              Option<List<FunctionalRef>> opt_overloadings, 
     106                             List<Overloading> interp_overloadings, 
    98107                             List<Overloading> newOverloadings, 
    99108                             Option<Type> type_result) { 
    100109 
    101         Collections.<Overloading>sort(newOverloadings, overloadComparator); 
    102         fns = Useful.applyToAll(newOverloadings, overloadingToIdOrOp); 
    103  
    104         if (newOverloadings.size() > 1) { 
     110        List<Overloading> the_overloads = forInterpreter ? interp_overloadings : newOverloadings; 
     111         
     112        Collections.<Overloading>sort(the_overloads, overloadComparator); 
     113        fns = Useful.applyToAll(the_overloads, overloadingToIdOrOp); 
     114 
     115        if (the_overloads.size() > 1) { 
    105116            // Collections.<IdOrOp>sort(fns, NodeComparator.idOrOpComparer); 
    106117            StringBuffer buffer = new StringBuffer(); 
     
    116127            String overloadingName = buffer.toString(); 
    117128            if (!overloadedFunctions.containsKey(overloadingName)) { 
    118                 overloadedFunctions.put(newOverloadings, new TypedIdOrOpList(overloadingName, fns, that.getInfo().getExprType())); 
     129                overloadedFunctions.put(the_overloads, new TypedIdOrOpList(overloadingName, fns, that.getInfo().getExprType())); 
    119130            } 
    120131            IdOrOp overloadingId = NodeFactory.makeId(NodeUtil.getSpan(that), overloadingName); 
    121132            fns = Collections.unmodifiableList(Collections.singletonList(overloadingId)); 
    122         } else if (newOverloadings.size() == 1 ){ 
    123             IdOrOp thename = newOverloadings.get(0).getUnambiguousName(); 
     133        } else if (the_overloads.size() == 1 ){ 
     134            IdOrOp thename = the_overloads.get(0).getUnambiguousName(); 
    124135            fns = Collections.unmodifiableList(Collections.singletonList(thename)); 
    125136        } else { 
     
    128139 
    129140        return super.forFnRefOnly(that, info, staticArgs , originalName, fns, 
    130                 opt_overloadings, Collections.<Overloading>emptyList(), type_result); 
     141                Collections.<Overloading>emptyList(), Collections.<Overloading>emptyList(), type_result); 
    131142    } 
    132143 
     
    135146    public Node forOpRefOnly(OpRef that, ExprInfo info, 
    136147                             List<StaticArg> staticArgs, IdOrOp originalName, List<IdOrOp> ops, 
    137                              Option<List<FunctionalRef>> opt_overloadings, 
     148                             List<Overloading>  interp_overloadings, 
    138149                             List<Overloading> newOverloadings, 
    139150                             Option<Type> type_result) { 
    140151        Op originalOp = (Op)originalName; 
    141         Collections.<Overloading>sort(newOverloadings, overloadComparator); 
    142         ops = Useful.applyToAll(newOverloadings, overloadingToIdOrOp); 
     152         
     153        List<Overloading> the_overloads = forInterpreter ? interp_overloadings : newOverloadings; 
     154 
     155        Collections.<Overloading>sort(the_overloads, overloadComparator); 
     156        ops = Useful.applyToAll(the_overloads, overloadingToIdOrOp); 
    143157        List<IdOrOp> newOps = new ArrayList<IdOrOp>(); 
    144158        List<Overloading> newNewOverloadings = new ArrayList<Overloading>(); 
     
    148162            if (OprUtil.equal(op_i.getFixity(), originalOp.getFixity())) { 
    149163                newOps.add(op_i); 
    150                 newNewOverloadings.add(newOverloadings.get(i)); 
     164                newNewOverloadings.add(the_overloads.get(i)); 
    151165            } 
    152166        } 
    153167 
    154168        ops = new ArrayList<IdOrOp>(); 
    155         newOverloadings = new ArrayList<Overloading>(); 
     169        the_overloads = new ArrayList<Overloading>(); 
    156170        ops.addAll(newOps); 
    157         newOverloadings.addAll(newNewOverloadings); 
    158  
    159        if (newOverloadings.size() > 1) { 
     171        the_overloads.addAll(newNewOverloadings); 
     172 
     173       if (the_overloads.size() > 1) { 
    160174            // Collections.<IdOrOp>sort(ops, NodeComparator.idOrOpComparer); 
    161175 
     
    172186            String overloadingName = buffer.toString(); 
    173187            if (!overloadedOperators.containsKey(overloadingName)) { 
    174                 overloadedOperators.put(newOverloadings, new TypedIdOrOpList(overloadingName, ops, that.getInfo().getExprType())); 
     188                overloadedOperators.put(the_overloads, new TypedIdOrOpList(overloadingName, ops, that.getInfo().getExprType())); 
    175189            } 
    176190            IdOrOp overloadingOp = NodeFactory.makeOp(NodeFactory.makeSpan(that), overloadingName); 
     
    178192       } 
    179193        return super.forOpRefOnly(that, info, staticArgs, originalName, ops, 
    180                                   opt_overloadings, newOverloadings, type_result); 
     194                                  // interp_overloadings, newOverloadings, 
     195                                  Collections.<Overloading>emptyList(), Collections.<Overloading>emptyList(), 
     196                                  type_result); 
    181197    } 
    182198 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/OverloadRewriter.java

    r4007 r4296  
    5656    public static ComponentResult 
    5757        rewriteComponents(Map<APIName, ComponentIndex> components, 
    58                           GlobalEnvironment env) 
     58                          GlobalEnvironment env, boolean forInterpreter) 
    5959    { 
    6060        HashSet<Component> rewrittenComponents = new HashSet<Component>(); 
     
    6262 
    6363        for (APIName componentName : components.keySet()) { 
    64             Component rewrite = rewriteComponent(components.get(componentName), env); 
     64            Component rewrite = rewriteComponent(components.get(componentName), env, forInterpreter); 
    6565            rewrittenComponents.add(rewrite); 
    6666        } 
     
    7171    } 
    7272 
    73     public static Component rewriteComponent(ComponentIndex component, 
    74                                              GlobalEnvironment env) { 
     73    private static Component rewriteComponent(ComponentIndex component, 
     74                                             GlobalEnvironment env, boolean forInterpreter) { 
    7575        Component comp = (Component) component.ast(); 
    76         OverloadRewriteVisitor visitor = new OverloadRewriteVisitor(); 
     76        OverloadRewriteVisitor visitor = new OverloadRewriteVisitor(forInterpreter); 
    7777        comp = (Component) comp.accept(visitor); 
    7878        List<Decl> decls = comp.getDecls(); 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/StaticChecker.java

    r4251 r4296  
    255255                Component component_ast = (Component)ast; 
    256256                if ( ! Shell.getScala() ) { 
    257                     // typecheck... 
    258                     result = typeCheck(componentIndex, env, traitTable, component_ast, false); 
    259                     // then replace inference variables... 
    260                     InferenceVarReplacer rep = new InferenceVarReplacer(result.getIVarResults()); 
    261                     ast = (Component)result.ast().accept(rep); 
    262                     componentIndex = (ComponentIndex)buildIndex(ast, isApi); 
    263                     // then typecheck again!!! 
    264                     result = typeCheck(componentIndex, env, traitTable, 
    265                                        component_ast, true); 
     257                    throw new Error("The Java version of the type checker is gone now."); 
    266258                } else { 
    267259                    STypeEnv typeEnv = STypeEnv$.MODULE$.make(componentIndex); 
     
    319311    } 
    320312 
    321     private static TypeCheckerResult typeCheck(ComponentIndex component, 
    322                                                GlobalEnvironment env, 
    323                                                TraitTable traitTable, 
    324                                                Node component_ast, 
    325                                                boolean postInference) { 
    326         TypeEnv typeEnv = typeCheckEnv(component, env); 
    327         TypeChecker typeChecker = new TypeChecker(traitTable, typeEnv, 
    328                                                   component, postInference); 
    329         return component_ast.accept(typeChecker); 
    330     } 
    331  
    332313    private static TypeEnv typeCheckEnv(ComponentIndex component, 
    333314                                        GlobalEnvironment env) { 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/StaticTestSuite.java

    r3400 r4296  
    3434 
    3535import com.sun.fortress.Shell; 
     36import com.sun.fortress.compiler.phases.PhaseOrder; 
    3637import com.sun.fortress.exceptions.StaticError; 
    3738import com.sun.fortress.exceptions.MultipleStaticError; 
     
    334335        private Iterable<? extends StaticError> compile(File f) 
    335336                throws IOException, UserError { 
     337            Shell.setPhaseOrder(PhaseOrder.interpreterPhaseOrder); 
    336338            return Shell.compilerPhases(ProjectProperties.SOURCE_PATH.prepend(f.getParent()), 
    337339                                        f.getName()); 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/codegen/GenericNumberer.java

    r4218 r4296  
    116116         
    117117        // what about overloadings? 
    118         Option<List<FunctionalRef>> overloadings_result = recurOnOptionOfListOfFunctionalRef(that.getOverloadings()); 
     118        List<Overloading> overloadings_result = recurOnListOfOverloading(that.getInterpOverloadings()); 
    119119        List<Overloading> newOverloadings_result = recurOnListOfOverloading(that.getNewOverloadings()); 
    120120         
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/desugarer/DesugaringVisitor.java

    r4280 r4296  
    501501                             List<StaticArg> staticArgs_result, 
    502502                             IdOrOp fnResult, List<IdOrOp> fns_result, 
    503                              Option<List<FunctionalRef>> overloadings_result, 
     503                             List<Overloading> interpOverloadings_result, 
    504504                             List<Overloading> newOverloadings_result, 
    505505                             Option<Type> type_result) { 
     
    520520            return ExprFactory.makeFnRef(that, NodeUtil.getExprType(that), 
    521521                                         mangleName(name), newFns, 
    522                                          staticArgs_result, overloadings_result, newOverloadings_result); 
     522                                         staticArgs_result, interpOverloadings_result, newOverloadings_result); 
    523523        } else { 
    524524            return that; 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/environments/TopLevelEnvGen.java

    r4169 r4296  
    229229        for (IdOrOpOrAnonymousName id : compUnitIndex.functions().firstSet()) { 
    230230            String idString = NodeUtil.nameString(id); 
     231            Set<Function> fns = compUnitIndex.functions().matchFirst(id); 
    231232            idStringSet.add(idString); 
    232233        } 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/phases/OverloadRewritingPhase.java

    r4002 r4296  
    3737 
    3838        OverloadRewriter.ComponentResult results = 
    39                 OverloadRewriter.rewriteComponents(previous.components(), env); 
     39                OverloadRewriter.rewriteComponents(previous.components(), env, false); 
    4040 
    4141        if (!results.isSuccessful()) { 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/phases/PhaseOrder.java

    r3998 r4296  
    6262     */ 
    6363    OVERLOADREWRITE("Overloading Rewriting"), 
     64     
     65    OVERLOADREWRITE_FOR_INTERPRETER("Overloading Rewriting For Interpreter"), 
    6466    /* Generate top level environments 
    6567     * Generates a Java bytecode compiled environment. 
     
    8284    } 
    8385 
    84     public Phase makePhase(FortressRepository repository, 
    85                            GlobalEnvironment env, Iterable<Api> apis, 
    86                            Iterable<Component> components, long lastModified) 
    87             throws StaticError { 
    88         Phase empty = new EmptyPhase(env, apis, components, lastModified); 
    89         switch (this) { 
    90             case EMPTY: 
    91                 return empty; 
    92             default: 
    93                 return makePhaseHelper(empty); 
     86//    public Phase makePhase(FortressRepository repository, 
     87//                           GlobalEnvironment env, Iterable<Api> apis, 
     88//                           Iterable<Component> components, long lastModified) 
     89//            throws StaticError { 
     90//        Phase empty = new EmptyPhase(env, apis, components, lastModified); 
     91//        switch (this) { 
     92//            case EMPTY: 
     93//                return empty; 
     94//            default: 
     95//                return makePhaseHelper(empty); 
     96//        } 
     97//    } 
     98 
     99    static public PhaseOrder[] disambiguatePhaseOrder = { 
     100        PREDISAMBIGUATEDESUGAR, 
     101        DISAMBIGUATE 
     102    }; 
     103     
     104    static public PhaseOrder[] grammarPhaseOrder = { 
     105        PREDISAMBIGUATEDESUGAR, 
     106        DISAMBIGUATE, 
     107        GRAMMAR 
     108    }; 
     109 
     110     static public PhaseOrder[] typecheckPhaseOrder = { 
     111        PREDISAMBIGUATEDESUGAR, 
     112        DISAMBIGUATE, 
     113        GRAMMAR, 
     114        PRETYPECHECKDESUGAR, 
     115        TYPECHECK 
     116    }; 
     117      
     118     static public PhaseOrder[] desugarPhaseOrder = { 
     119         PREDISAMBIGUATEDESUGAR, 
     120         DISAMBIGUATE, 
     121         GRAMMAR, 
     122         PRETYPECHECKDESUGAR, 
     123         TYPECHECK, 
     124         DESUGAR, 
     125     }; 
     126  
     127    static public PhaseOrder[] interpreterPhaseOrder = { 
     128            PREDISAMBIGUATEDESUGAR, 
     129            DISAMBIGUATE, 
     130            GRAMMAR, 
     131            PRETYPECHECKDESUGAR, 
     132            TYPECHECK, 
     133            DESUGAR, 
     134            OVERLOADREWRITE_FOR_INTERPRETER, 
     135            ENVGEN 
     136    }; 
     137     
     138   static public PhaseOrder[] compilerPhaseOrder = { 
     139        PREDISAMBIGUATEDESUGAR, 
     140        DISAMBIGUATE, 
     141        GRAMMAR, 
     142        PRETYPECHECKDESUGAR, 
     143        TYPECHECK, 
     144        DESUGAR, 
     145        OVERLOADREWRITE, 
     146        CODEGEN 
     147    }; 
     148     
     149 
     150   
     151  
     152 
     153    public static Phase makePhaseOrder(PhaseOrder[] order, 
     154            FortressRepository repository, 
     155            GlobalEnvironment env, 
     156            Iterable<Api> apis, 
     157            Iterable<Component> components, 
     158            long lastModified) { 
     159        Phase phase = new EmptyPhase(env, apis, components, lastModified); 
     160         
     161        for (int i = 0; i < order.length; i++) { 
     162            phase = order[i].makePhaseOrderHelper(phase); 
    94163        } 
    95     } 
    96  
    97     private Phase makePhaseHelper(Phase phase) { 
     164         
     165        return phase; 
     166    } 
     167 
     168    private Phase makePhaseOrderHelper(Phase phase) { 
    98169        switch (this) { 
    99170            case EMPTY: 
    100171                return phase; 
    101172            case PREDISAMBIGUATEDESUGAR: 
    102                 return new PreDisambiguationDesugarPhase(EMPTY.makePhaseHelper(phase)); 
     173                return new PreDisambiguationDesugarPhase(phase); 
    103174            case DISAMBIGUATE: 
    104                 return new DisambiguatePhase(PREDISAMBIGUATEDESUGAR.makePhaseHelper(phase)); 
     175                return new DisambiguatePhase(phase); 
    105176            case GRAMMAR: 
    106                 return new GrammarPhase(DISAMBIGUATE.makePhaseHelper(phase)); 
     177                return new GrammarPhase(phase); 
    107178            case PRETYPECHECKDESUGAR: 
    108                 return new PreTypeCheckDesugarPhase(GRAMMAR.makePhaseHelper(phase)); 
     179                return new PreTypeCheckDesugarPhase(phase); 
    109180            case TYPECHECK: 
    110                 return new TypeCheckPhase(PRETYPECHECKDESUGAR.makePhaseHelper(phase)); 
     181                return new TypeCheckPhase(phase); 
    111182            case DESUGAR: 
    112                 return new DesugarPhase(TYPECHECK.makePhaseHelper(phase)); 
     183                return new DesugarPhase(phase); 
    113184            case OVERLOADREWRITE: 
    114                 return new OverloadRewritingPhase(DESUGAR.makePhaseHelper(phase)); 
     185                return new OverloadRewritingPhase(phase); 
     186                 
     187            case OVERLOADREWRITE_FOR_INTERPRETER: 
     188                return new OverloadRewritingForInterpreterPhase(phase); 
    115189            case ENVGEN: 
    116                 return new EnvGenerationPhase(OVERLOADREWRITE.makePhaseHelper(phase)); 
     190                return new EnvGenerationPhase(phase); 
    117191            case CODEGEN: 
    118                 return new CodeGenerationPhase(ENVGEN.makePhaseHelper(phase)); 
     192                return new CodeGenerationPhase(phase); 
    119193            default: 
    120194                return InterpreterBug.bug("Unknown static analysis phase: " 
     
    122196        } 
    123197    } 
     198     
     199 
    124200 
    125201    @Override 
  • trunk/ProjectFortress/src/com/sun/fortress/compiler/typechecker/TypeChecker.java

    r4285 r4296  
    9393 *   cases of the typechecker that create open constraints must close those constraints immediately.<br> 
    9494 */ 
    95 public class TypeChecker extends NodeDepthFirstVisitor<TypeCheckerResult> { 
    96  
    97     private static boolean isPostInference(FunctionalRef opref) { 
    98         return opref.getOverloadings().isSome(); 
    99     } 
    100  
    101     private static TypeChecker addSelf(TypeChecker newChecker, Type self_type){ 
    102         return newChecker.extend(Collections.singletonList(NodeFactory.makeLValue("self", self_type))); 
    103     } 
    104     /** Returns an error result if item is NOT an ExprMI */ 
    105     private static Option<TypeCheckerResult> expectExprMI(MathItem item) { 
    106         boolean is_expr_item = isExprMI(item); 
    107         if( !is_expr_item ) { 
    108             String err = "Item at this location must be an expression, not an operator."; 
    109             TypeCheckerResult err_result = new TypeCheckerResult(item,TypeError.make(err, item)); 
    110             return Option.some(err_result); 
    111         } 
    112         else { 
    113             return Option.none(); 
    114         } 
    115     } 
    116     /** Returns an error result if item is NOT a ParenthesisDelimitedMI */ 
    117     private static Option<TypeCheckerResult> expectParenedExprItem(MathItem item) { 
    118         boolean is_parened = isParenedExprItem(item); 
    119         if( !is_parened ) { 
    120             String err = "Argument to function must be parenthesized."; 
    121             TypeCheckerResult err_result = new TypeCheckerResult(item, TypeError.make(err, item)); 
    122             return Option.some(err_result); 
    123         } 
    124         else { 
    125             return Option.none(); 
    126         } 
    127     } 
    128     static private Type getTypeOfLValue(LValue lval) { 
    129             return lval.getIdType().unwrap(); 
    130     } 
    131     private static boolean isExprMI(MathItem item) { 
    132         return item.accept(new NodeDepthFirstVisitor<Boolean>(){ 
    133             @Override public Boolean defaultCase(Node that) { return false; } 
    134             @Override public Boolean forNonParenthesisDelimitedMI(NonParenthesisDelimitedMI that) { return true; } 
    135             @Override public Boolean forParenthesisDelimitedMI(ParenthesisDelimitedMI that) { return true; } 
    136         }); 
    137     } 
    138     private static boolean isParenedExprItem(MathItem item) { 
    139         return item.accept(new NodeDepthFirstVisitor<Boolean>(){ 
    140             @Override public Boolean defaultCase(Node that) { return false; } 
    141             @Override public Boolean forParenthesisDelimitedMI(ParenthesisDelimitedMI that) { return true; } 
    142         }); 
    143     } 
    144  
    145     private static Type typeFromLValues(Span span, List<LValue> bindings) { 
    146         List<Type> results = new ArrayList<Type>(); 
    147  
    148         for (LValue binding: bindings) { 
    149             if (binding.getIdType().isSome()) { 
    150                 results.add(binding.getIdType().unwrap()); 
    151             } else 
    152                 bug(binding, "Missing type."); 
    153         } 
    154         return NodeFactory.makeTupleType(span, results); 
    155     } 
    156  
    157     private final CompilationUnitIndex compilationUnit; 
    158  
    159     private final Map<Id, Option<Set<Type>>> labelExitTypes; // Note: this is mutable state. 
    160  
    161     private final boolean postInference; // Is this pass of the typechecker a post-inference pass? 
    162  
    163     private final TypeAnalyzer subtypeChecker; 
    164  
    165     private TraitTable table; 
    166  
    167     private TypeEnv typeEnv; 
    168  
    169     // An informative constraint passed down the ast 
    170     private final ConstraintFormula downwardConstraint; 
    171  
    172     public TypeChecker(TraitTable table, 
    173             TypeEnv typeEnv, 
    174             CompilationUnitIndex compilationUnit, 
    175             boolean postInference) { 
    176         this.table = table; 
    177         this.typeEnv = typeEnv; 
    178         this.compilationUnit = compilationUnit; 
    179         this.subtypeChecker = TypeAnalyzer.make(table); 
    180         this.labelExitTypes = new HashMap<Id, Option<Set<Type>>>(); 
    181         this.postInference = postInference; 
    182         this.downwardConstraint = trueFormula(); 
    183     } 
    184  
    185     private TypeChecker(TraitTable table, 
    186             TypeEnv typeEnv, 
    187             CompilationUnitIndex compilationUnit, 
    188             TypeAnalyzer subtypeChecker, 
    189             Map<Id, Option<Set<Type>>> labelExitTypes, 
    190             boolean postInference, 
    191             ConstraintFormula downwardsConstraint) { 
    192         this.table = table; 
    193         this.typeEnv = typeEnv; 
    194         this.compilationUnit = compilationUnit; 
    195         this.subtypeChecker = subtypeChecker; 
    196         this.labelExitTypes = labelExitTypes; 
    197         this.postInference = postInference; 
    198         this.downwardConstraint = downwardsConstraint; 
    199     } 
    200  
    201     /** 
    202      * Checks whether all the expressions in the block have type void. 
    203      * List of Exprs passed in so that error messages can be more accurate. 
    204      */ 
    205     private List<TypeCheckerResult> allVoidButLast(List<TypeCheckerResult> results, List<Expr> block){ 
    206         // every other expression except for the last must be void 
    207         List<TypeCheckerResult> all_results = new ArrayList<TypeCheckerResult>(); 
    208         String void_err = "All expressions except the last in a block must have () type."; 
    209         for( int i=0; i<results.size()-1; i++ ) { 
    210             TypeCheckerResult r_i = results.get(i); 
    211             if( r_i.type().isSome() ) { 
    212                 all_results.add(this.checkSubtype(r_i.type().unwrap(), 
    213                         Types.VOID, block.get(i), void_err)); 
    214             } 
    215         } 
    216         return all_results; 
    217     } 
    218  
    219     /** 
    220      * For method calls, return a constraint formula matching the parameters to 
    221      * the type of the argument. Assumes that this is being used for a method call, 
    222      * because it makes some assumptions about the type of the argument. 
    223      */ 
    224     private ConstraintFormula argsMatchParams(List<Param> params, Type arg_type) { 
    225         final int arg_size; 
    226         if( arg_type instanceof TupleType ) 
    227             arg_size = ((TupleType)arg_type).getElements().size(); 
    228         else 
    229             arg_size = 1; 
    230  
    231         //handle domain 
    232         Type domain_type; 
    233         if(!params.isEmpty()) { 
    234  
    235             // Regular parameters & var args 
    236             List<Type> param_types = 
    237                 IterUtil.fold(params, new LinkedList<Type>(), new Lambda2<LinkedList<Type>,Param,LinkedList<Type>>(){ 
    238                     // How many types have we accumulated thus far? 
    239                     int typeCount = 0; 
    240  
    241                     public LinkedList<Type> value(LinkedList<Type> arg0, Param arg1) { 
    242                                             if( ! NodeUtil.isVarargsParam(arg1) ) { 
    243                             typeCount++; 
    244                             arg0.add(arg1.getIdType().unwrap()); 
    245                             return arg0; 
    246                         } 
    247                                             else { // a varargs param, add until the sizes are equal 
    248                             int to_add = arg_size - typeCount; 
    249                             while( to_add > 0 ) { 
    250                                                             arg0.add(arg1.getVarargsType().unwrap()); 
    251                                 to_add--; 
    252                             } 
    253                             return arg0; 
    254                         } 
    255                     }}); 
    256  
    257             //handle defaults (nyi) 
    258             if( NodeUtil.isVarargsParam(params.get(params.size()-1)) 
    259                            && params.get(params.size()-1).getDefaultExpr().isSome()){ 
    260                 return NI.nyi(); 
    261             } 
    262  
    263             domain_type = NodeFactory.makeTupleType(NodeUtil.getSpan(arg_type),param_types); 
    264         } 
    265         else { 
    266             //is void 
    267             domain_type = Types.VOID; 
    268         } 
    269         return this.subtypeChecker.subtype(arg_type, domain_type); 
    270     } 
    271  
    272     /** 
    273      * Return a failing TypecheckerResult with error message if the given type {@code t} is 
    274      * not a trait. 
    275      */ 
    276     private TypeCheckerResult assertTrait(BaseType t, Node ast, String msg, Node error_loc) { 
    277         TypeCheckerResult err_result = new TypeCheckerResult(ast, TypeError.make(msg, error_loc)); 
    278  
    279         if( !(t instanceof TraitType || t instanceof AnyType) ) 
    280             return err_result; 
    281  
    282         Option<TypeConsIndex> type_cons_; 
    283         if ( t instanceof TraitType ) 
    284             type_cons_ = this.table.typeCons(((TraitType)t).getName()); 
    285         else // t instanceof AnyType 
    286             type_cons_ = this.table.typeCons(Types.ANY_NAME); 
    287         if( type_cons_.isSome() && type_cons_.unwrap() instanceof ProperTraitIndex ) { 
    288             return new TypeCheckerResult(ast); 
    289         } 
    290         else { 
    291             return err_result; 
    292         } 
    293     } 
    294  
    295     // Checks the chunk given, and returns the result and a new expression. 
    296     // Requires that all TypeCheckerResults passed in actually have a type. 
    297     // Must be called on non-empty list. 
    298     private Pair<TypeCheckerResult,Expr> checkChunk(List<Pair<TypeCheckerResult,Expr>> chunk, FunctionalRef infix_juxt) { 
    299         assert(!chunk.isEmpty()); 
    300         // The non-functions in each chunk, if any, are replaced by a single element consisting of the non-functions grouped 
    301         // left-associatively into binary juxtapositions. 
    302         Option<Expr> last_non_fn = Option.none(); 
    303         List<Expr> fns = new LinkedList<Expr>(); 
    304         for( Pair<TypeCheckerResult,Expr> chunk_element : chunk ) { 
    305             if( !TypesUtil.isArrows(chunk_element.first().type().unwrap()) ) { 
    306                 // If we've already seen an expr, created a binary juxt with previous 
    307                 if( last_non_fn.isNone() ) 
    308                     last_non_fn = Option.some(chunk_element.second()); 
    309                 else 
    310                     last_non_fn = Option.<Expr>some(ExprFactory.makeOpExpr(infix_juxt, 
    311                                                                                                last_non_fn.unwrap(), 
    312                                                                                                chunk_element.second())); 
    313             } 
    314             else { 
    315                 fns.add(chunk_element.second()); 
    316             } 
    317         } 
    318         // What remains in each chunk is then grouped right-associatively, as fn applications. 
    319         Option<Expr> result_expr = last_non_fn; 
    320         Collections.reverse(fns); // reverse so right assoc becomes left assoc 
    321         for( Expr fn : fns ) { 
    322             if( result_expr.isNone() ) 
    323                 result_expr = Option.some(fn); 
    324             else 
    325                 result_expr = Option.<Expr>some(ExprFactory.make_RewriteFnApp(fn, result_expr.unwrap())); 
    326         } 
    327         // We are done. result_expr must be some or this method wasn't implemented correctly. 
    328         TypeCheckerResult result = TypeCheckerResult.compose(result_expr.unwrap(), subtypeChecker, 
    329                 CollectUtil.makeList(IterUtil.pairFirsts(chunk))); 
    330         return Pair.make(result, result_expr.unwrap()); 
    331     } 
    332  
    333     /** 
    334      * Check the subtype relation for the given types.  If subtype <: supertype, then a TypeCheckerResult 
    335      * for the given node and corresponding type constraints will be returned.  Otherwise, a TypeCheckerResult 
    336      * for the given node with a generic error message will be returned. 
    337      */ 
    338     private TypeCheckerResult checkSubtype(Type subtype, Type supertype, Node ast) { 
    339         // System.err.println("checkSubtype(" + subtype + "," + supertype + "," + ast); 
    340  
    341         return checkSubtype(subtype, 
    342                 supertype, 
    343                 ast, 
    344                 errorMsg("Expected expression of type ", supertype, " ", 
    345                         "but was type ", subtype)); 
    346     } 
    347  
    348     /** 
    349      * Check the subtype relation for the given types.  If subtype <: supertype, then a TypeCheckerResult 
    350      * for the given node and corresponding type constraints will be returned.  Otherwise, a TypeCheckerResult 
    351      * for the given node with the a TypeError and the given error message will be returned. 
    352      */ 
    353     private TypeCheckerResult checkSubtype(Type subtype, Type supertype, Node ast, String error) { 
    354         // System.err.println("checkSubtype(" + subtype + "," + supertype + "," + ast + "," + error); 
    355  
    356         ConstraintFormula constraint = subtypeChecker.subtype(subtype, supertype); 
    357         if( !constraint.isSatisfiable() ) { 
    358             // note that if it's satisfiable, it could still be later found to not be 
    359             return new TypeCheckerResult(ast, TypeError.make(error, ast)); 
    360         } else { 
    361             return new TypeCheckerResult(ast, constraint); 
    362         } 
    363     } 
    364  
    365     /** 
    366      * Check the subtype relation for the given types.  If subtype <: supertype, then a TypeCheckerResult 
    367      * for the given node and corresponding type constraints will be returned, and the type of this node 
    368      * will be the given type resultType.  Otherwise, a TypeCheckerResult 
    369      * for the given node with the a TypeError and the given error message will be returned. 
    370      */ 
    371     private TypeCheckerResult checkSubtype(Type subtype, Type supertype, Node ast, Type resultType, String error) { 
    372         ConstraintFormula constraint = subtypeChecker.subtype(subtype, supertype); 
    373         if( !constraint.isSatisfiable() ) { 
    374             // note that if it's satisfiable, it could still be later found to not be 
    375             return new TypeCheckerResult(ast, resultType, TypeError.make(error, ast)); 
    376         } else { 
    377             return new TypeCheckerResult(ast, resultType, constraint); 
    378         } 
    379     } 
    380  
    381     public TypeAnalyzer typeAnalyzer() { 
    382         return subtypeChecker; 
    383     } 
    384  
    385     @Override 
    386     public TypeCheckerResult defaultCase(Node that) { 
    387         return new TypeCheckerResult(that); 
    388     } 
    389  
    390     private List<TraitIndex> expectTraitIndeces(List<TraitType> traits) { 
    391         List<TraitIndex> result = new ArrayList<TraitIndex>(traits.size()); 
    392         for( TraitType type : traits ) { 
    393             result.add(expectTraitIndex(type)); 
    394         } 
    395         return result; 
    396     } 
    397  
    398     /** 
    399      * Look up the index of the given type, expecting it to exist. If it 
    400      * does not, that represents a bug. 
    401      */ 
    402     private TraitIndex expectTraitIndex(TraitType trait) { 
    403         Option<TypeConsIndex> tc_ = table.typeCons(trait.getName()); 
    404         if( tc_.isNone()) { 
    405             return bug("An expected trait index is not in table: " + trait); 
    406         } 
    407         else if (!(tc_.unwrap() instanceof TraitIndex)) { 
    408             return bug("Expected a trait index; given " + tc_.unwrap()); 
    409         } 
    410         else { 
    411             return (TraitIndex)tc_.unwrap(); 
    412         } 
    413     } 
    414  
    415     /** Check for ^ followed by ^ or ^ followed by [], both static errors. */ 
    416     private Option<TypeCheckerResult> exponentiationStaticCheck(Node ast, List<MathItem> items) { 
    417  
    418         //Visitor checks for two exponentiations or an exponentiation and a subscript in a row 
    419         NodeDepthFirstVisitor<TypeCheckerResult> static_error = new NodeDepthFirstVisitor<TypeCheckerResult>() { 
    420             Option<Node> exponent = Option.none(); 
    421             @Override 
    422             public TypeCheckerResult defaultCase(Node that) { 
    423                 exponent=Option.none(); 
    424                 return new TypeCheckerResult(that); 
    425             } 
    426  
    427             @Override 
    428             public TypeCheckerResult forExponentiationMI(ExponentiationMI that) { 
    429                 if(exponent.isNone()){ 
    430                     exponent=Option.<Node>some(that); 
    431                     return new TypeCheckerResult(that); 
    432                 } 
    433                 else{ 
    434                     String err_message = "Two consecutive ^s."; 
    435                     StaticError err=TypeError.make(err_message, 
    436                                                    NodeUtil.getSpan(that)); 
    437                     return new TypeCheckerResult(that,err); 
    438                 } 
    439             } 
    440  
    441             @Override 
    442             public TypeCheckerResult forSubscriptingMI(SubscriptingMI that) { 
    443                 if(exponent.isNone()){ 
    444                     return new TypeCheckerResult(that); 
    445                 } 
    446                 else{ 
    447                     String err_message = "Exponentiation followed by subscripting is illegal."; 
    448                     StaticError err=TypeError.make(err_message, 
    449                                                    NodeUtil.getSpan(that)); 
    450                     exponent = Option.none(); 
    451                     return new TypeCheckerResult(that,err); 
    452                 } 
    453             } 
    454         }; 
    455         List<TypeCheckerResult> static_errors = static_error.recurOnListOfMathItem(items); 
    456         TypeCheckerResult static_error_result = TypeCheckerResult.compose(ast, subtypeChecker, static_errors); 
    457         if(!static_error_result.isSuccessful()){ 
    458             return Option.some(static_error_result); 
    459         } 
    460         else { 
    461             return Option.none(); 
    462         } 
    463     } 
    464  
    465     private TypeChecker extend(List<LValue> bindings) { 
    466         return new TypeChecker(table, 
    467                 typeEnv.extendWithLValues(bindings), 
    468                 compilationUnit, 
    469                 subtypeChecker, 
    470                 labelExitTypes, 
    471                 postInference, 
    472                 downwardConstraint); 
    473     } 
    474  
    475     private TypeChecker extend(List<StaticParam> newStaticParams, List<Param> newParams, Option<WhereClause> whereClause) { 
    476         return new TypeChecker(table, 
    477                 typeEnv.extendWithParams(newParams).extendWithStaticParams(newStaticParams), 
    478                 compilationUnit, 
    479                 subtypeChecker.extend(newStaticParams, whereClause), 
    480                 labelExitTypes, 
    481                 postInference, 
    482                 downwardConstraint); 
    483     } 
    484  
    485     private TypeChecker extend(List<StaticParam> newStaticParams, Option<List<Param>> newParams, Option<WhereClause> whereClause) { 
    486         return new TypeChecker(table, 
    487                 typeEnv.extend(newParams).extendWithStaticParams(newStaticParams), 
    488                 compilationUnit, 
    489                 subtypeChecker.extend(newStaticParams, whereClause), 
    490                 labelExitTypes, 
    491                 postInference, 
    492                 downwardConstraint); 
    493     } 
    494  
    495     private TypeChecker extend(List<StaticParam> newStaticParams, Option<WhereClause> whereClause) { 
    496         return new TypeChecker(table, 
    497                 typeEnv.extendWithStaticParams(newStaticParams), 
    498                 compilationUnit, 
    499                 subtypeChecker.extend(newStaticParams, whereClause), 
    500                 labelExitTypes, 
    501                 postInference, 
    502                 downwardConstraint); 
    503     } 
    504  
    505     private TypeChecker extend(LocalVarDecl decl) { 
    506         return new TypeChecker(table, 
    507                 typeEnv.extend(decl), 
    508                 compilationUnit, 
    509                 subtypeChecker, 
    510                 labelExitTypes, 
    511                 postInference, 
    512                 downwardConstraint); 
    513     } 
    514  
    515     private TypeChecker extend(Param newParam) { 
    516         return new TypeChecker(table, 
    517                 typeEnv.extend(newParam), 
    518                 compilationUnit, 
    519                 subtypeChecker, 
    520                 labelExitTypes, 
    521                 postInference, 
    522                 downwardConstraint); 
    523     } 
    524  
    525     private TypeChecker extend(Option<WhereClause> whereClause) { 
    526         return new TypeChecker(table, 
    527                 typeEnv, 
    528                 compilationUnit, 
    529                 subtypeChecker.extend(Collections.<StaticParam>emptyList(), whereClause), 
    530                 labelExitTypes, 
    531                 postInference, 
    532                 downwardConstraint); 
    533     } 
    534  
    535     public TypeChecker extendWithFnDecls(Relation<IdOrOpOrAnonymousName, FnDecl> fns) { 
    536         return new TypeChecker(table, 
    537                 typeEnv.extendWithFnDecls(fns), 
    538                 compilationUnit, 
    539                 subtypeChecker, 
    540                 labelExitTypes, 
    541                 postInference, 
    542                 downwardConstraint); 
    543     } 
    544  
    545     public TypeChecker extendWithFunctions(Relation<IdOrOpOrAnonymousName, FunctionalMethod> methods) { 
    546         return new TypeChecker(table, 
    547                 typeEnv.extendWithFunctions(methods), 
    548                 compilationUnit, 
    549                 subtypeChecker, 
    550                 labelExitTypes, 
    551                 postInference, 
    552                 downwardConstraint); 
    553     } 
    554  
    555     public TypeChecker extendWithMethods(Relation<IdOrOpOrAnonymousName, Method> methods) { 
    556         return new TypeChecker(table, 
    557                 typeEnv.extendWithMethods(methods), 
    558                 compilationUnit, 
    559                 subtypeChecker, 
    560                 labelExitTypes, 
    561                 postInference, 
    562                 downwardConstraint); 
    563     } 
    564  
    565     public TypeChecker extendWithout(Node declSite, Set<? extends IdOrOpOrAnonymousName> names) { 
    566         return new TypeChecker(table, 
    567                 typeEnv.extendWithout(declSite, names), 
    568                 compilationUnit, 
    569                 subtypeChecker, 
    570                 labelExitTypes, 
    571                 postInference, 
    572                 downwardConstraint); 
    573     } 
    574  
    575     public TypeChecker extendWithConstraints(Iterable<ConstraintFormula> constraints) { 
    576         constraints = IterUtil.compose(downwardConstraint, constraints); 
    577         ConstraintFormula new_constraint = bigAnd(constraints, 
    578                 new SubtypeHistory(subtypeChecker)); 
    579         return new TypeChecker(table, 
    580                 typeEnv, 
    581                 compilationUnit, 
    582                 subtypeChecker, 
    583                 labelExitTypes, 
    584                 postInference, 
    585                 new_constraint); 
    586     } 
    587  
    588     private Option<Type> findFieldInTraitHierarchy(List<TraitType> supers, FieldRef thatFieldRef) { 
    589  
    590         List<TraitType> new_supers = new ArrayList<TraitType>(); 
    591         for( TraitType my_super : supers ) { 
    592             TraitIndex index = expectTraitIndex(my_super); 
    593  
    594             final List<StaticParam> trait_static_params = index.staticParameters(); 
    595             final List<StaticArg> trait_static_args = my_super.getArgs(); 
    596  
    597             // Map to list of supertypes 
    598             for( TraitTypeWhere ttw : index.extendsTypes() ) { 
    599                 Type t = ttw.getBaseType(); 
    600                 Type t_ = (Type)t.accept(new StaticTypeReplacer(trait_static_params, trait_static_args)); 
    601                 new_supers.addAll(traitTypesCallable(t_)); 
    602             } 
    603  
    604             // check if trait has a getter 
    605             Map<Id,Method> getters=index.getters(); 
    606             if(getters.containsKey(thatFieldRef.getField())) { 
    607                 Method field=(Method)getters.get(thatFieldRef.getField()).instantiate(trait_static_params, trait_static_args); 
    608                 return Option.some(field.getReturnType().unwrap()); 
    609             } 
    610             else { 
    611                 //check if trait is an object 
    612                 if(index instanceof ObjectTraitIndex) { 
    613                     //Check if object has field 
    614                     ObjectTraitIndex object_index=(ObjectTraitIndex)index; 
    615                     Map<Id,Variable> fields=object_index.fields(); 
    616                     if(fields.containsKey(thatFieldRef.getField())){ 
    617                         Variable field=fields.get(thatFieldRef.getField()); 
    618  
    619                         if( field instanceof ParamVariable ) { 
    620                             ParamVariable param = (ParamVariable)field; 
    621                             Param field_node = param.ast(); 
    622  
    623                             Type field_type = 
    624                                 field_node.accept(new NodeAbstractVisitor<Type>() { 
    625                                     @Override 
    626                                     public Type forParam(Param that) { 
    627                                                                             if ( NodeUtil.isVarargsParam(that) ) 
    628                                                                                 return that.getIdType().unwrap(); 
    629                                                                             else 
    630                                                                                 return that.getVarargsType().unwrap(); 
    631                                                                         } 
    632                                 }); 
    633  
    634                             return Option.some(field_type); 
    635                         } 
    636                         else if( field instanceof DeclaredVariable ) { 
    637                             DeclaredVariable var = (DeclaredVariable)field; 
    638                             LValue bind = var.ast(); 
    639                             return Option.some(bind.getIdType().unwrap()); 
    640                         } 
    641                         else { 
    642                             return bug("Field of an object should not be a Singleton Object." + field); 
    643                         } 
    644                     } 
    645                 } 
    646                 //error no such field 
    647  
    648             } 
    649         } 
    650  
    651         if(!new_supers.isEmpty() ) { 
    652             // recur 
    653             return this.findFieldInTraitHierarchy(new_supers, thatFieldRef); 
    654         } 
    655         else { 
    656             return Option.none(); 
    657         } 
    658     } 
    659  
    660     // This method does a lot: Basically all of the hard work of finding an appropriate overloading, including looking 
    661     // in parent traits. 
    662     // TODO: This method is in need of a serious overhaul. It is way too similar to 
    663     // TypesUtil.applicationType... 
    664     private Pair<List<Method>,List<TypeCheckerResult>> findMethodsInTraitHierarchy(final IdOrOpOrAnonymousName method_name, List<TraitType> supers, 
    665             Type arg_type, List<StaticArg> in_static_args, 
    666             final Node that) { 
    667         final List<TypeCheckerResult> all_results= new ArrayList<TypeCheckerResult>(); 
    668         List<Method> candidates=new ArrayList<Method>(); 
    669         List<TraitType> new_supers=new ArrayList<TraitType>(); 
    670         SubtypeHistory history = new SubtypeHistory(subtypeChecker); 
    671  
    672         for(TraitType type: supers) { 
    673             TraitIndex trait_index = expectTraitIndex(type); 
    674  
    675             final List<StaticArg> extended_type_args = type.getArgs(); 
    676             final List<StaticParam> extended_type_params = trait_index.staticParameters(); 
    677             // get all of the types this type extends. Note that because we can extend types with our own static args, 
    678             // we must visit the extended type with a static type replacer. 
    679             for( TraitTypeWhere ttw : trait_index.extendsTypes() ) { 
    680                 Type t = (Type)ttw.getBaseType().accept(new StaticTypeReplacer(extended_type_params, extended_type_args)); 
    681                 new_supers.addAll(traitTypesCallable(t)); 
    682             } 
    683  
    684             // Get methods with the right name: 
    685             // Add all dotted methods, 
    686             Set<? extends Method> methods_with_name = trait_index.dottedMethods().matchFirst(method_name); 
    687  
    688             for( Method m : methods_with_name ) { 
    689                 List<StaticArg> static_args = new ArrayList<StaticArg>(in_static_args); 
    690                 // same number of static args 
    691                 if( m.staticParameters().size() > 0 && in_static_args.size() == 0 ) { 
    692                     // we need to infer static arguments 
    693  
    694                     List<StaticArg> static_inference_params = 
    695                         CollectUtil.makeList( 
    696                                 IterUtil.map(m.staticParameters(), new Lambda<StaticParam,StaticArg>(){ 
    697                                     public StaticArg value(StaticParam arg0) { 
    698                                         // TODO if parameters are anything but TypeParam, we don't know 
    699                                         // how to infer it yet. 
    700                                         // Otherwise, we've got all static parameters 
    701                                                                             if( NodeUtil.isTypeParam(arg0) ){ 
    702                                             Set<BaseType> bounds = CollectUtil.asSet(arg0.getExtendsClause()); 
    703                                             Type ivt = NodeFactory.make_InferenceVarType(NodeUtil.getSpan(method_name)); 
    704                                             ConstraintFormula constraint=TypeChecker.this.subtypeChecker.subtype(ivt, NodeFactory.makeIntersectionType(bounds)); 
    705                                             all_results.add(new TypeCheckerResult(that, Option.<Type>none(), constraint)); 
    706                                             return NodeFactory.makeTypeArg(NodeFactory.makeSpan(ivt), ivt); 
    707                                         } 
    708                                         else{ 
    709                                             return NI.nyi(); 
    710                                         } 
    711                                     }})); 
    712                     static_args = static_inference_params; 
    713                 } 
    714                 else if(m.staticParameters().size()!=static_args.size()) { 
    715                     // we don't need to infer, and they have different numbers of args 
    716                     continue; 
    717                 } 
    718                 // instantiate method params with method and type args 
    719                 Functional im_maybe = m.instantiate(Useful.concat(m.staticParameters(), extended_type_params), 
    720                         Useful.concat(static_args, extended_type_args)); 
    721                 // we know this cast works, instantiate contract 
    722                 Method im = (Method)im_maybe; 
    723                 // Do they have the same number of parameters, or at least can they be matched. 
    724                 ConstraintFormula mc = this.argsMatchParams(im.parameters(), arg_type); 
    725                 // constraint & any relevent downward constraints satisfiable? 
    726                 if(mc.and(downwardConstraint, history) .isSatisfiable()) { 
    727                     //add method to candidates 
    728                     candidates.add(im); 
    729                     all_results.add(new TypeCheckerResult(that,Option.<Type>none(),mc)); 
    730                 } 
    731  
    732             } 
    733         } 
    734         //If you have a super type check it for overloadings 
    735         if(!new_supers.isEmpty()){ 
    736  
    737             Pair<List<Method>, List<TypeCheckerResult>> temp = findMethodsInTraitHierarchy(method_name, new_supers, arg_type, in_static_args, that); 
    738             candidates.addAll(temp.first()); 
    739             all_results.addAll(all_results); 
    740         } 
    741         return Pair.make(candidates,all_results); 
    742     } 
    743  
    744     private TypeCheckerResult findSetterInTraitHierarchy(IdOrOpOrAnonymousName field_name, List<TraitType> supers, 
    745             Type arg_type, Node ast){ 
    746         List<TraitType> new_supers = new ArrayList<TraitType>(); 
    747         for( TraitType my_super : supers ) { 
    748             TraitIndex trait_index = expectTraitIndex(my_super); 
    749  
    750  
    751             // Map to list of supertypes 
    752             for( TraitTypeWhere ttw : trait_index.extendsTypes() ) { 
    753                 new_supers.addAll(traitTypesCallable(ttw.getBaseType())); 
    754             } 
    755  
    756             // check if trait has a getter 
    757             Map<Id,Method> setters=trait_index.setters(); 
    758             if(setters.containsKey(field_name)) { 
    759                 Method field=setters.get(field_name); 
    760                 ConstraintFormula works =  argsMatchParams(field.parameters(),arg_type); 
    761                 if(!works.isSatisfiable()){ 
    762                     String errmes = "Argument to setter has wrong type"; 
    763                     StaticError err = TypeError.make(errmes, ast); 
    764                     return new TypeCheckerResult(ast,Option.<Type>none(),Collections.singletonList(err),works); 
    765                 } 
    766                 else{ 
    767                     return new TypeCheckerResult(ast,works); 
    768                 } 
    769             } 
    770             else { 
    771                 // we used to check for a field but we don't think that's right. 
    772                 //check if trait is an object 
    773                 //                 if(trait_index instanceof ObjectTraitIndex){ 
    774                 //                 //Check if object has field 
    775                 //                 ObjectTraitIndex object_index=(ObjectTraitIndex)trait_index; 
    776                 //                 Map<Id,Variable> fields=object_index.fields(); 
    777                 //                 if(fields.containsKey(field_name)){ 
    778                 //                 Variable field=fields.get(field_name); 
    779                 //                 Option<BindingLookup> type=this.typeEnv.binding(field_name); 
    780                 //                 return this.checkSubtype(arg_type,type.unwrap().getType().unwrap(),ast, "Argument to field has wrong type"); 
    781                 //                 } 
    782                 //                 } 
    783                 //error no such field 
    784             } 
    785             //error receiver not a trait 
    786         } 
    787  
    788         if(!new_supers.isEmpty() ) { 
    789             // recur 
    790             return this.findSetterInTraitHierarchy(field_name, new_supers, arg_type, ast ); 
    791         } 
    792         else { 
    793             String errmes = "Setter for field "+ field_name +" not found."; 
    794             return new TypeCheckerResult(ast,TypeError.make(errmes, ast)); 
    795         } 
    796  
    797     } 
    798  
    799     /** 
    800      * Given a list of functional refs and the argument to which they are to be applied, find the FunctionalRef 
    801      * whose type is the statically most applicable to the given arg. 
    802      */ 
    803     private TypeCheckerResult findStaticallyMostApplicableFn(List<? extends Pair<? extends FunctionalRef, Type>> fns, Type arg_type, FunctionalRef ref, IdOrOp name) { 
    804         final List<Pair<FunctionalRef, Type>> pruned_fns = new ArrayList<Pair<FunctionalRef, Type>>(fns.size()); 
    805         // prune down the list of fns to just the ones that apply 
    806         for( Pair<? extends FunctionalRef, Type> fn : fns ) { 
    807             // If applicationType indicates the method applies, we keep it in pruned_fns 
    808             Type fn_type = fn.second(); 
    809             Option<?> applies = TypesUtil.applicationType(subtypeChecker, fn_type, new ArgList(arg_type), downwardConstraint); 
    810             if( applies.isSome() ) 
    811                 pruned_fns.add(Pair.<FunctionalRef, Type>make(fn.first(), fn_type)); 
    812         } 
    813  
    814         if( pruned_fns.isEmpty() ){ 
    815             //No statically most applicable Fn 
    816             String err = "No applicable overloading of " + name + " exists for argument of type " + arg_type.toString(); 
    817             TypeCheckerResult err_result = new TypeCheckerResult(ref, TypeError.make(err, ref)); 
    818             return TypeCheckerResult.compose(ref, subtypeChecker, err_result); 
    819         } 
    820         // then, find the one with out of that group with the most specific arguments. 
    821         final Box<Option<Pair<FunctionalRef, Type>>> most_applicable = new Box<Option<Pair<FunctionalRef, Type>>>(){ 
    822             private Option<Pair<FunctionalRef, Type>> ma = none(); 
    823             public void set(Option<Pair<FunctionalRef, Type>> arg0) { ma = arg0; } 
    824             public Option<Pair<FunctionalRef, Type>> value() { return ma; } 
    825         }; 
    826         // Loops through all the pruned_fns finding one with the most specific arg type 
    827         for( final Pair<FunctionalRef, Type> pruned_fn : pruned_fns ) { 
    828             Type cur_type_ = pruned_fn.second(); 
    829             for( final Type cur_type : TypesUtil.conjuncts(cur_type_) ) { 
    830                 cur_type.accept(new TypeAbstractVisitor_void() { 
    831                     @Override 
    832                     public void forArrowType(final ArrowType cur_type) { 
    833                         if( most_applicable.value().isNone() ) { 
    834                             most_applicable.set(some(Pair.<FunctionalRef,Type>make(pruned_fn.first(), cur_type))); 
    835                             return; 
    836                         } 
    837                         // do some gnarly double dispatch 
    838                         most_applicable.value().unwrap().second().accept(new TypeAbstractVisitor_void() { 
    839                             @Override 
    840                             public void forArrowType(ArrowType most_appl) { 
    841                                 // Where is arg of cur_type <: arg of most_appl? 
    842                                 ConstraintFormula sub = 
    843                                     subtypeChecker.subtype(Types.stripKeywords(cur_type.getDomain()), 
    844                                             Types.stripKeywords(most_appl.getDomain())); 
    845                                 if( sub.solve().isTrue() ) { 
    846                                     // TODO: We should actually throw an error if they are equal! 
    847                                     most_applicable.set(some(Pair.<FunctionalRef,Type>make(pruned_fn.first(), cur_type))); 
    848                                 } 
    849                             } 
    850                             @Override public void forType(Type that) { bug("An applicable function should have an arrow type: " + that); } 
    851                         }); 
    852                     } 
    853                     @Override public void forType(Type that) { 
    854                         bug("An applicable function should have an arrow type: " + that); 
    855                     } 
    856                 }); 
    857             } 
    858         } 
    859         // Unwrap should always work b/c we already tested pruned_fns for empty, and 
    860         // on the first iteration of the loop, most_applicable is always set to some. 
    861         return new TypeCheckerResult(most_applicable.value().unwrap().first(), most_applicable.value().unwrap().second()); 
    862     } 
    863  
    864     private static List<Pair<FunctionalRef, Type>> destructFnOverloadings(List<FunctionalRef> overloadings) { 
    865         List<Pair<FunctionalRef, Type>> result = new ArrayList<Pair<FunctionalRef, Type>>(overloadings.size()); 
    866         for( FunctionalRef overloading : overloadings ) { 
    867                     if ( overloading.getOverloadingType().isNone() ) 
    868                         bug(overloading, 
    869                             "Type checker should have type for the overloading of " 
    870                             + overloading.getOriginalName()); 
    871                     result.add(Pair.make(overloading, overloading.getOverloadingType().unwrap())); 
    872         } 
    873         return result; 
    874     } 
    875  
    876     @Override 
    877     public TypeCheckerResult for_RewriteFnApp(_RewriteFnApp that) { 
    878         TypeCheckerResult arg_result = recur(that.getArgument()); 
    879  
    880         if( postInference && that.getFunction() instanceof FnRef && 
    881                     isPostInference((FnRef)that.getFunction()) ) { 
    882                     FnRef fns = (FnRef)that.getFunction(); 
    883             // if we have finished typechecking, and we have encountered a reference to an overloaded function 
    884  
    885             if( !arg_result.isSuccessful() ) { 
    886                 return TypeCheckerResult.compose(that, subtypeChecker, arg_result); 
    887             } 
    888  
    889             Type arg_type = arg_result.type().unwrap(); 
    890             TypeCheckerResult fn_result = findStaticallyMostApplicableFn(destructFnOverloadings(fns.getOverloadings().unwrap()), 
    891                                                                                      arg_type, fns, fns.getOriginalName()); 
    892             // Now just check the rewritten expression by the normal means 
    893             return for_RewriteFnAppOnly(that, Option.<TypeCheckerResult>none(), fn_result, arg_result); 
    894         } 
    895         else { 
    896             // Add constraints from the arguments, since they may affect overloading choice 
    897                     TypeCheckerResult fn_result = recur(that.getFunction()); 
    898             Iterable<ConstraintFormula> arg_constraint = Collections.singletonList(arg_result.getNodeConstraints()); 
    899             //debugging 
    900             ConstraintFormula temp = trueFormula(); 
    901             for(ConstraintFormula i: arg_constraint){ 
    902                 temp.and(i, new SubtypeHistory(subtypeChecker)); 
    903             } 
    904             Boolean blah = temp.isSatisfiable(); 
    905             //end debugging 
    906             return this.extendWithConstraints(arg_constraint).for_RewriteFnAppOnly(that, 
    907                     Option.<TypeCheckerResult>none(), fn_result, arg_result); 
    908         } 
    909     } 
    910  
    911     public TypeCheckerResult for_RewriteFnAppOnly(_RewriteFnApp that, Option<TypeCheckerResult> exprType_result, 
    912             TypeCheckerResult function_result, TypeCheckerResult argument_result) { 
    913         // check sub expressions 
    914         if( function_result.type().isNone() || argument_result.type().isNone() ) 
    915             return TypeCheckerResult.compose(that, subtypeChecker, function_result, argument_result); 
    916         Option<Pair<Type,ConstraintFormula>> app_result = 
    917             TypesUtil.applicationType(subtypeChecker, function_result.type().unwrap(), 
    918                     new ArgList(argument_result.type().unwrap()), downwardConstraint); 
    919         Option<Type> result_type; 
    920         TypeCheckerResult result; 
    921  
    922         if( app_result.isSome() ) { 
    923             result = new TypeCheckerResult(that,app_result.unwrap().second()); 
    924             result_type = Option.some(app_result.unwrap().first()); 
    925         } 
    926         else { 
    927             String err = "Applicable overloading of function " + that.getFunction() + 
    928                 " could not be found for argument type " + normalize(argument_result.type().unwrap()); // error message needs work 
    929             result = new TypeCheckerResult(that, TypeError.make(err, that)); 
    930             result_type = Option.none(); 
    931         } 
    932  
    933         _RewriteFnApp new_node = ExprFactory.make_RewriteFnApp(NodeUtil.getSpan(that), 
    934                 NodeUtil.isParenthesized(that), 
    935                 result_type, 
    936                 (Expr) function_result.ast(), 
    937                 (Expr) argument_result.ast()); 
    938  
    939         // On the post-inference pass, an application could produce Inference vars 
    940         TypeCheckerResult successful = new TypeCheckerResult(that); 
    941         if( postInference && TypesUtil.containsInferenceVarTypes(new_node) ) { 
    942             // close constraints 
    943             Pair<Boolean,Node> temp1 = TypesUtil.closeConstraints(new_node, subtypeChecker, function_result, argument_result, result); 
    944             new_node = (_RewriteFnApp)temp1.second(); 
    945             Boolean ok = temp1.first(); 
    946             if(result_type.isSome()){ 
    947                 Pair<Boolean,Node> temp2 = TypesUtil.closeConstraints(result_type.unwrap(), subtypeChecker, function_result, argument_result, result); 
    948                 result_type = Option.some((Type)temp2.second()); 
    949                 ok&=temp2.first(); 
    950             } 
    951             if(!ok){ 
    952                 String err = "Applicable overloading of function " + that.getFunction() + " could not be found for argument type " + argument_result.type(); 
    953                 successful = new TypeCheckerResult(that,TypeError.make(err, that)); 
    954             } 
    955         } 
    956  
    957         return TypeCheckerResult.compose(new_node, result_type, 
    958                 subtypeChecker, function_result, argument_result, result, successful); 
    959     } 
    960  
    961     public TypeCheckerResult for_RewriteObjectRefOnly(VarRef that, TypeCheckerResult exprType_result, 
    962                                                           TypeCheckerResult obj_result, 
    963                                                           List<TypeCheckerResult> staticArgs_result) { 
    964             Type t; 
    965             ConstraintFormula accumulated_constraints = trueFormula(); 
    966             if( obj_result.type().isNone() ) { 
    967                 return TypeCheckerResult.compose(that, subtypeChecker, obj_result, 
    968                                                  TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); 
    969             } 
    970             else if( (obj_result.type().unwrap() instanceof TraitType) ) { 
    971                 t=obj_result.type().unwrap(); 
    972                 TraitType _t = (TraitType)t; 
    973  
    974                 if ( NodeUtil.isGenericSingletonType(_t) ) { 
    975                     // instantiate with static parameters 
    976                     Option<ConstraintFormula> constraint = StaticTypeReplacer.argsMatchParams(that.getStaticArgs(), 
    977                                                                                               _t.getStaticParams(), 
    978                                                                                               this.subtypeChecker); 
    979                     if(constraint.isSome()) { 
    980                         // make a trait type that is GenericType instantiated 
    981                         t = NodeFactory.makeTraitType(NodeUtil.getSpan(_t), 
    982                                                       NodeUtil.isParenthesized(_t), 
    983                                                       _t.getName(), 
    984                                                       that.getStaticArgs()); 
    985                         accumulated_constraints = constraint.unwrap(); 
    986                     } 
    987                     else { 
    988                         // error 
    989                         String err = "Generic object, " + _t + " instantiated with invalid arguments, " + that.getStaticArgs(); 
    990                         TypeCheckerResult e_result = new TypeCheckerResult(that, TypeError.make(err, that)); 
    991                         return TypeCheckerResult.compose(that, subtypeChecker, obj_result, e_result, 
    992                                                          TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); 
    993                     } 
    994                 } 
    995             } 
    996             else { 
    997                 return bug("Unexpected type for ObjectRef."); 
    998             } 
    999  
    1000             Node new_node = ExprFactory.makeVarRef(NodeUtil.getSpan(that), NodeUtil.isParenthesized(that), 
    1001                                                    Option.<Type>some(t), 
    1002                                                    (Id) obj_result.ast(), 
    1003                                                    (List<StaticArg>) TypeCheckerResult.astFromResults(staticArgs_result), 
    1004                                                    that.getLexicalDepth()); 
    1005             return TypeCheckerResult.compose(new_node, t, subtypeChecker, obj_result, 
    1006                                              TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result), 
    1007                                              new TypeCheckerResult(new_node,accumulated_constraints)); 
    1008     } 
    1009  
    1010     @Override 
    1011     public TypeCheckerResult forAmbiguousMultifixOpExpr(final AmbiguousMultifixOpExpr that) { 
    1012         // See if we can successfully typecheck this expression as a multifix one. 
    1013         TypeCheckerResult multi_result = 
    1014             (ExprFactory.makeOpExpr(NodeUtil.getSpan(that), 
    1015                                                 NodeUtil.isParenthesized(that), 
    1016                                                 NodeUtil.getExprType(that), 
    1017                                                 that.getMultifix_op(), 
    1018                                                 that.getArgs()).accept(this)); 
    1019  
    1020         if( multi_result.isSuccessful() ) { 
    1021             return multi_result; 
    1022         } 
    1023         else { 
    1024             if( that.getArgs().size() < 2 ) 
    1025                 bug("This never should have been neither multifix nor infix."); 
    1026  
    1027             // If not, do it as a collection of left-associated infix expressions 
    1028             return 
    1029             IterUtil.fold(IterUtil.skipFirst(that.getArgs()), IterUtil.first(that.getArgs()), 
    1030                     new Lambda2<Expr,Expr,Expr>(){ 
    1031                 public Expr value(Expr arg0, Expr arg1) { 
    1032                     return ExprFactory.makeOpExpr(that.getInfix_op(), arg0, arg1); 
    1033                 }}).accept(this); 
    1034         } 
    1035  
    1036         //I am pretty sure this method rebuilds the ast correctly and fills in the exprType field without any changes 
    1037  
    1038     } 
    1039  
    1040     @Override 
    1041     public TypeCheckerResult forAnyType(AnyType that) { 
    1042         return new TypeCheckerResult(that); 
    1043     } 
    1044  
    1045     @Override 
    1046     public TypeCheckerResult forAPIName(APIName that) { 
    1047         return new TypeCheckerResult(that); 
    1048     } 
    1049  
    1050     // This case is only called for single element arrays ( e.g., [5] ) 
    1051     // and not for pieces of ArrayElements 
    1052     @Override 
    1053     public TypeCheckerResult forArrayElementOnly(ArrayElement that, TypeCheckerResult exprType_result, 
    1054             List<TypeCheckerResult> staticArgs_result, 
    1055             TypeCheckerResult element_result) { 
    1056  
    1057         if( element_result.type().isNone() ) { 
    1058             return TypeCheckerResult.compose(that, subtypeChecker, element_result, 
    1059                     TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); 
    1060         } 
    1061  
    1062         List<StaticArg> staticArgs = that.getStaticArgs(); 
    1063         Id array = Types.getArrayKName(1); 
    1064         Option<TypeConsIndex> ind=table.typeCons(array); 
    1065         if(ind.isNone()){ 
    1066             array = Types.ARRAY_NAME; 
    1067             ind = table.typeCons(array); 
    1068             if(ind.isNone()){ 
    1069                 bug(array+"not in table"); 
    1070             } 
    1071         } 
    1072         TraitIndex index = (TraitIndex)ind.unwrap(); 
    1073         if(staticArgs.isEmpty()){ 
    1074             TypeArg elem = NodeFactory.makeTypeArg(element_result.type().unwrap()); 
    1075             IntArg lower = NodeFactory.makeIntArgVal(NodeUtil.getSpan(that),""+0); 
    1076             IntArg size = NodeFactory.makeIntArgVal(NodeUtil.getSpan(that),""+1); 
    1077             Type t=Types.makeArrayKType(1, Useful.list(elem, lower, size)); 
    1078             Node new_node=ExprFactory.makeArrayElement(NodeUtil.getSpan(that), NodeUtil.isParenthesized(that), 
    1079                                                                    Option.some(t), 
    1080                                                                    (List<StaticArg>) TypeCheckerResult.astFromResults(staticArgs_result), 
    1081                                                                    (Expr) element_result.ast()); 
    1082             return TypeCheckerResult.compose(new_node,t,this.subtypeChecker, element_result); 
    1083         } 
    1084         else{ 
    1085             Option<ConstraintFormula> constraint = StaticTypeReplacer.argsMatchParams(that.getStaticArgs(), index.staticParameters(), this.subtypeChecker); 
    1086             if(constraint.isSome()){ 
    1087                 TypeCheckerResult res=this.checkSubtype(element_result.type().unwrap(), 
    1088                         ((TypeArg)that.getStaticArgs().get(0)).getTypeArg(), that, 
    1089                         element_result.type().unwrap()+" must be a subtype of "+((TypeArg)that.getStaticArgs().get(0)).getTypeArg()); 
    1090                 Type t=Types.makeArrayKType(1, that.getStaticArgs()); 
    1091                 Node new_node=ExprFactory.makeArrayElement(NodeUtil.getSpan(that), NodeUtil.isParenthesized(that), 
    1092                                                                            Option.some(t), 
    1093                                                                            (List<StaticArg>) TypeCheckerResult.astFromResults(staticArgs_result), 
    1094                                                                            (Expr) element_result.ast()); 
    1095                 return TypeCheckerResult.compose(new_node,t,this.subtypeChecker, element_result, res, 
    1096                         TypeCheckerResult.compose(new_node,this.subtypeChecker,staticArgs_result), 
    1097                         new TypeCheckerResult(new_node, constraint.unwrap())); 
    1098             } 
    1099             else{ 
    1100                 String err = "Explicit static arguments do not match required arguments for Array1 (" + index.staticParameters() + ".)"; 
    1101                 TypeCheckerResult err_result = new TypeCheckerResult(that, TypeError.make(err, that)); 
    1102                 return TypeCheckerResult.compose(that, subtypeChecker, err_result, element_result, 
    1103                         TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); 
    1104             } 
    1105         } 
    1106     } 
    1107  
    1108  
    1109     // This method is pretty long because we have to create a new visitor that visits ArrayElements and ArrayElement 
    1110     // knowing that we are inside of another ArrayElement. 
    1111  
    1112     private static Pair<Type,List<BigInteger>> getTypeAndBoundsFromArray(Type that){ 
    1113         TraitType type; 
    1114         if(that instanceof TraitType){ 
    1115             type=(TraitType)that; 
    1116         } 
    1117         else{ 
    1118             return InterpreterBug.bug("Not an Array"); 
    1119         } 
    1120         if(type.getName().toString().startsWith("FortressLibrary.Array")){ 
    1121             List<BigInteger> dims = new ArrayList<BigInteger>(); 
    1122             for(int i=2; i<type.getArgs().size(); i+=2){ 
    1123                 StaticArg arg = type.getArgs().get(i); 
    1124                 if(arg instanceof IntArg){ 
    1125                     IntExpr iexpr = ((IntArg)arg).getIntVal(); 
    1126                     if(iexpr instanceof IntBase){ 
    1127                         IntLiteralExpr dim = ((IntBase) iexpr).getIntVal(); 
    1128                         BigInteger n = dim.getIntVal(); 
    1129                         dims.add(n); 
    1130                     } 
    1131                     else{ 
    1132                         return NI.nyi(); 
    1133                     } 
    1134                 } 
    1135                 else{ 
    1136                     return InterpreterBug.bug("Array type changed"); 
    1137                 } 
    1138             } 
    1139             Type t; 
    1140             if(type.getArgs().get(0) instanceof TypeArg){ 
    1141                 t = ((TypeArg)type.getArgs().get(0)).getTypeArg(); 
    1142             } 
    1143             else{ 
    1144                 return InterpreterBug.bug("Array type changed"); 
    1145             } 
    1146             return Pair.make(t, dims); 
    1147         } 
    1148         else{ 
    1149             return InterpreterBug.bug("Not an Array"); 
    1150         } 
    1151     } 
    1152  
    1153     @Override 
    1154     public TypeCheckerResult forArrayElements(ArrayElements that){ 
    1155             Span span = NodeUtil.getSpan(that); 
    1156         List<TypeCheckerResult> subarrays = this.recurOnListOfArrayExpr(that.getElements()); 
    1157         Lambda<TypeCheckerResult,Option<Pair<Type,List<BigInteger>>>> get = new Lambda<TypeCheckerResult,Option<Pair<Type,List<BigInteger>>>>(){ 
    1158             public Option<Pair<Type, List<BigInteger>>> value(TypeCheckerResult arg0) { 
    1159                 if(arg0.type().isSome()){ 
    1160                     return Option.some(TypeChecker.this.getTypeAndBoundsFromArray(arg0.type().unwrap())); 
    1161                 } 
    1162                 else{ 
    1163                     return Option.none(); 
    1164                 } 
    1165             } 
    1166         }; 
    1167         Iterable <Option<Pair<Type, List<BigInteger>>>> temp = IterUtil.map(subarrays, get); 
    1168         List<Type> types = new ArrayList<Type>(); 
    1169         List<List<BigInteger>> dims = new ArrayList<List<BigInteger>>(); 
    1170         boolean failed=false; 
    1171         List<TypeCheckerResult> all_results = new ArrayList<TypeCheckerResult>(subarrays); 
    1172         for(Option<Pair<Type,List<BigInteger>>> i: temp){ 
    1173             if(i.isNone()){ 
    1174                 //one of your subarrays already failed 
    1175                 failed=true; 
    1176             } 
    1177             else{ 
    1178                 types.add(i.unwrap().first()); 
    1179                 dims.add(i.unwrap().second()); 
    1180             } 
    1181         } 
    1182         List<BigInteger> first = dims.get(0); 
    1183         Boolean same_size = true; 
    1184         for(List<BigInteger> f: dims){ 
    1185             same_size&=f.equals(first); 
    1186         } 
    1187         Type array_type = this.subtypeChecker.join(types); 
    1188  
    1189         if(!same_size){ 
    1190             all_results.add(new TypeCheckerResult(that, TypeError.make("Not all subarrays the same size ", that))); 
    1191         } 
    1192  
    1193  
    1194  
    1195         // Now try to get array type for the dimension we have 
    1196         int dim = that.getDimension(); 
    1197         Id array = Types.getArrayKName(dim); 
    1198         Option<TypeConsIndex> ind=table.typeCons(array); 
    1199         if(ind.isNone()){ 
    1200             array = Types.ARRAY_NAME; 
    1201             ind = table.typeCons(array); 
    1202             if(ind.isNone()){ 
    1203                 bug(array+"not in table"); 
    1204             } 
    1205         } 
    1206  
    1207         TraitIndex trait_index = (TraitIndex)ind.unwrap(); 
    1208  
    1209  
    1210         Type return_type; 
    1211         ConstraintFormula accumulated_constraints = trueFormula(); 
    1212         if(that.getStaticArgs().isEmpty()){ 
    1213             if(failed || !same_size){ 
    1214                 return TypeCheckerResult.compose(that, subtypeChecker, all_results); 
    1215             } 
    1216             // then we just use what we determine to be true 
    1217             List<StaticArg> inferred_args = new ArrayList<StaticArg>(1+dim*2); 
    1218             inferred_args.add(NodeFactory.makeTypeArg(array_type)); 
    1219             IntArg lower_bound = NodeFactory.makeIntArgVal(span,"0"); 
    1220             IntArg size = NodeFactory.makeIntArgVal(span, 
    1221                                                                 ((Integer)subarrays.size()).toString()); 
    1222             inferred_args.add(lower_bound); 
    1223             inferred_args.add(size); 
    1224             for(int i=0;i<dim-1;i++) { 
    1225                 BigInteger s = first.get(i); 
    1226                 lower_bound = NodeFactory.makeIntArgVal(span,"0"); 
    1227                 size = NodeFactory.makeIntArgVal(span,s.toString()); 
    1228                 inferred_args.add(lower_bound); 
    1229                 inferred_args.add(size); 
    1230             } 
    1231             // then instantiate and return 
    1232             return_type = Types.makeArrayKType(dim, inferred_args); 
    1233         } 
    1234         else{ 
    1235             List<StaticArg> sargs = that.getStaticArgs(); 
    1236             Option<ConstraintFormula> constraints = StaticTypeReplacer.argsMatchParams(sargs, trait_index.staticParameters(), this.subtypeChecker); 
    1237             if(constraints.isSome()) { 
    1238                 // First arg MUST BE a TypeArg, and it must be a supertype of the elements 
    1239                 Type declared_type = ((TypeArg)that.getStaticArgs().get(0)).getTypeArg(); 
    1240                 all_results.add(this.checkSubtype(array_type, declared_type, that, "Array elements must be a subtype of explicity declared type" + declared_type + ".")); 
    1241                 //Check infered dims against explicit dims 
    1242                 return_type = Types.makeArrayKType(dim, sargs); 
    1243                 accumulated_constraints=constraints.unwrap(); 
    1244             } 
    1245             else { 
    1246                 // wrong args passed 
    1247                 all_results.add(new TypeCheckerResult(that, TypeError.make("Explicit static arguments don't matched required arguments for " + trait_index + ".", that))); 
    1248                 return TypeCheckerResult.compose(that ,subtypeChecker, all_results); 
    1249             } 
    1250             if(failed || !same_size){ 
    1251                 return TypeCheckerResult.compose(that, Option.some(return_type) ,subtypeChecker, all_results); 
    1252             } 
    1253         } 
    1254  
    1255  
    1256  
    1257         Lambda<TypeCheckerResult,ArrayExpr> get_expr = new Lambda<TypeCheckerResult,ArrayExpr>(){ 
    1258             public ArrayExpr value(TypeCheckerResult arg0) { 
    1259                 return (ArrayExpr)arg0.ast(); 
    1260             } 
    1261         }; 
    1262         ArrayElements new_node=ExprFactory.makeArrayElements(NodeUtil.getSpan(that), 
    1263                                                                      NodeUtil.isParenthesized(that), 
    1264                                                                      Option.some(return_type) , 
    1265                                                                      that.getStaticArgs(), 
    1266                                                                      that.getDimension(), 
    1267                                                                      Useful.list(IterUtil.map(subarrays, get_expr)), 
    1268                                                                      that.isOutermost()); 
    1269  
    1270         all_results.add(new TypeCheckerResult(new_node, accumulated_constraints)); 
    1271  
    1272         return TypeCheckerResult.compose(new_node, Option.some(return_type) ,subtypeChecker, all_results); 
    1273  
    1274     } 
    1275  
    1276     @Override 
    1277     public TypeCheckerResult forAsExpr(AsExpr that) { 
    1278         Type ascriptedType = that.getAnnType(); 
    1279         TypeCheckerResult expr_result = that.getExpr().accept(this); 
    1280         Type exprType = expr_result.type().isSome() ? expr_result.type().unwrap() : Types.BOTTOM; 
    1281         // node rebuilding handled in forTypeAnnotatedExprOnly 
    1282         return forTypeAnnotatedExprOnly(that, 
    1283                 expr_result, 
    1284                 errorMsg("Attempt to ascribe expression of type ", 
    1285                         exprType, " to non-supertype ", ascriptedType)); 
    1286     } 
    1287  
    1288     @Override 
    1289     public TypeCheckerResult forAsIfExpr(AsIfExpr that) { 
    1290         Type assumedType = that.getAnnType(); 
    1291         TypeCheckerResult expr_result = that.getExpr().accept(this); 
    1292         Type exprType = expr_result.type().isSome() ? expr_result.type().unwrap() : Types.BOTTOM; 
    1293         // node rebuilding handled in forTypeAnnotatedExprOnly 
    1294         return forTypeAnnotatedExprOnly(that, 
    1295                 expr_result, 
    1296                 errorMsg("Attempt to assume type ", assumedType, 
    1297                         " from non-subtype ", exprType)); 
    1298     } 
    1299  
    1300     @Override 
    1301     public TypeCheckerResult forAssignment(Assignment that) { 
    1302             if ( postInference ) // postInference pass 
    1303                 return for_Assignment( that ); 
    1304  
    1305         Pair<List<Type>, TypeCheckerResult> tuple_types_ = requireTupleType(that.getRhs(), that.getLhs().size()); 
    1306  
    1307         // Get the types for the RHS, which must be a tuple if the LHS is 
    1308         TypeCheckerResult rhs_result = tuple_types_.second(); 
    1309         List<Type> rhs_types = tuple_types_.first(); 
    1310  
    1311         if( !rhs_result.isSuccessful() ) 
    1312             return TypeCheckerResult.compose(that, subtypeChecker, rhs_result); 
    1313         if( rhs_types.size() != that.getLhs().size() ) 
    1314             return bug("requireTupleType should always return a list of types equal to the size it is passed."); 
    1315  
    1316         List<TypeCheckerResult> lhs_results = new ArrayList<TypeCheckerResult>(that.getLhs().size()); 
    1317         List<FunctionalRef> op_refs = that.getAssignOp().isSome() ? new ArrayList<FunctionalRef>(that.getLhs().size()) : Collections.<FunctionalRef>emptyList(); 
    1318  
    1319         // Go through LHS, checking each one 
    1320         Iterator<Type> rhs_type_iter = rhs_types.iterator(); 
    1321         for( Lhs lhs : that.getLhs() ) { 
    1322             Type rhs_type = rhs_type_iter.next(); 
    1323             Pair<Option<FunctionalRef>, TypeCheckerResult> p = checkLhsAssignment(lhs, rhs_type, that.getAssignOp()); 
    1324             lhs_results.add(p.second()); 
    1325  
    1326             if( p.first().isSome() ) 
    1327                 op_refs.add(p.first().unwrap()); 
    1328         } 
    1329  
    1330         Assignment new_node; 
    1331         if( that.getAssignOp().isSome() ) { 
    1332             // Create a new Assignment, with an FunctionalRef for each LHS 
    1333             new_node = ExprFactory.makeAssignmentOld(NodeUtil.getSpan(that), 
    1334                                                   NodeUtil.isParenthesized(that), 
    1335                                                   Option.<Type>some(Types.VOID), 
    1336                                                   (List<Lhs>)TypeCheckerResult.astFromResults(lhs_results), 
    1337                                                   that.getAssignOp(), 
    1338                                                   (Expr)rhs_result.ast(), 
    1339                                                   op_refs); 
    1340         } 
    1341         else { 
    1342             // Create a new Assignment 
    1343             new_node = ExprFactory.makeAssignment(NodeUtil.getSpan(that), 
    1344                     NodeUtil.isParenthesized(that), 
    1345                     Option.<Type>some(Types.VOID), 
    1346                     (List<Lhs>)TypeCheckerResult.astFromResults(lhs_results), 
    1347                     that.getAssignOp(), 
    1348                     (Expr)rhs_result.ast(), 
    1349                     Collections.<CompoundAssignmentInfo>emptyList()); 
    1350         } 
    1351         // This case could not result in open constraints: If there is an FunctionalRef, this must not be 
    1352         // the postInference pass, because AssignmentNodes should exist instead. If there is 
    1353         // no FunctionalRef, then no open constraints can be created. 
    1354         return TypeCheckerResult.compose(new_node, Types.VOID, subtypeChecker, rhs_result, 
    1355                 TypeCheckerResult.compose(new_node, subtypeChecker, lhs_results)); 
    1356     } 
    1357  
    1358     private TypeCheckerResult for_Assignment(Assignment that) { 
    1359         Pair<List<Type>, TypeCheckerResult> tuple_types_ = requireTupleType(that.getRhs(), that.getLhs().size()); 
    1360  
    1361         // Get the types for the RHS, which must be a tuple if the LHS is 
    1362         TypeCheckerResult rhs_result = tuple_types_.second(); 
    1363         List<Type> rhs_types = tuple_types_.first(); 
    1364  
    1365         if( !rhs_result.isSuccessful() ) 
    1366             return TypeCheckerResult.compose(that, subtypeChecker, rhs_result); 
    1367         if( rhs_types.size() != that.getLhs().size() ) 
    1368             return bug("requireTupleType should always return a list of types equal to the size it is passed."); 
    1369  
    1370         List<TypeCheckerResult> lhs_results = new ArrayList<TypeCheckerResult>(that.getLhs().size()); 
    1371         List<FunctionalRef> op_refs = that.getAssignOp().isSome() ? new ArrayList<FunctionalRef>(that.getLhs().size()) : Collections.<FunctionalRef>emptyList(); 
    1372  
    1373         // Go through LHS, checking each one 
    1374         Iterator<Type> rhs_type_iter = rhs_types.iterator(); 
    1375         for( Lhs lhs : that.getLhs() ) { 
    1376             Type rhs_type = rhs_type_iter.next(); 
    1377             Pair<Option<FunctionalRef>, TypeCheckerResult> p = checkLhsAssignment(lhs, rhs_type, that.getAssignOp()); 
    1378             lhs_results.add(p.second()); 
    1379  
    1380             if( p.first().isSome() ) 
    1381                 op_refs.add(p.first().unwrap()); 
    1382         }; 
    1383  
    1384         // Create a Assignment, with an FunctionalRef for each LHS 
    1385         Assignment new_node = ExprFactory.makeAssignmentOld(NodeUtil.getSpan(that), 
    1386                                                      NodeUtil.isParenthesized(that), 
    1387                                                      Option.<Type>some(Types.VOID), 
    1388                                                      (List<Lhs>)TypeCheckerResult.astFromResults(lhs_results), 
    1389                                                      that.getAssignOp(), 
    1390                                                      (Expr)rhs_result.ast(), 
    1391                                                      op_refs); 
    1392  
    1393         TypeCheckerResult result = TypeCheckerResult.compose(new_node, Types.VOID, subtypeChecker, rhs_result, 
    1394                 TypeCheckerResult.compose(new_node, subtypeChecker, lhs_results)); 
    1395  
    1396         // The application of operators could cause Inference Vars to be introduced 
    1397         TypeCheckerResult successful = new TypeCheckerResult(that); 
    1398         if( postInference && TypesUtil.containsInferenceVarTypes(new_node) ) { 
    1399             Pair<Boolean,Node> temp = TypesUtil.closeConstraints(new_node, result); 
    1400             new_node = (Assignment)temp.second(); 
    1401             if(!temp.first()){ 
    1402                 String err = "No overloading for " + that.getAssignOp().unwrap(); 
    1403                 successful = new TypeCheckerResult(that, TypeError.make(err,that)); 
    1404             } 
    1405         } 
    1406         return TypeCheckerResult.compose(new_node, Types.VOID, subtypeChecker, result, successful); 
    1407     } 
    1408     /** 
    1409      * Checks that something of type rhs_type can be assigned to the given lhs. If opr is some, we have to 
    1410      * take that in to account as well. This method is still pretty complicated... 
    1411      */ 
    1412     private Pair<Option<FunctionalRef>, TypeCheckerResult> checkLhsAssignment(final Lhs lhs, final Type rhs_type, final Option<FunctionalRef> opr) { 
    1413  
    1414         // Different assignment rules for each type of LHS... 
    1415         Pair<TypeCheckerResult, Type> result_and_arg_type = lhs.accept(new NodeAbstractVisitor<Pair<TypeCheckerResult, Type>>(){ 
    1416             @Override public Pair<TypeCheckerResult, Type> forFieldRef(FieldRef that) { 
    1417                 TypeCheckerResult obj_result = recur(that.getObj()); 
    1418                 TypeCheckerResult field_result = recur(that); // only used for ast, and type if opr is SOME 
    1419                 if( !obj_result.isSuccessful() ) 
    1420                     return Pair.<TypeCheckerResult,Type>make(TypeCheckerResult.compose(that, subtypeChecker, obj_result), Types.BOTTOM); 
    1421  
    1422                 Type obj_type = obj_result.type().unwrap(); 
    1423                 List<TraitType> traits = traitTypesCallable(obj_type); 
    1424                 TypeCheckerResult r = findSetterInTraitHierarchy(that.getField(), traits, rhs_type, that); 
    1425  
    1426                 if( opr.isSome() && field_result.isSuccessful() ) { 
    1427                     // Return the type of the field for opr application 
    1428                     return Pair.<TypeCheckerResult,Type>make(TypeCheckerResult.compose(field_result.ast(), subtypeChecker, r, field_result, obj_result), field_result.type().unwrap()); 
    1429                 } 
    1430                 else if( opr.isSome() && !field_result.isSuccessful() ) { 
    1431                     return Pair.<TypeCheckerResult,Type>make(TypeCheckerResult.compose(that, subtypeChecker, r, field_result, obj_result), Types.BOTTOM); 
    1432                 } 
    1433                 else { 
    1434                     return Pair.<TypeCheckerResult, Type>make(TypeCheckerResult.compose(field_result.ast(), subtypeChecker, r, obj_result), Types.BOTTOM); 
    1435                 } 
    1436             } 
    1437  
    1438             @Override public Pair<TypeCheckerResult, Type> forLValue(LValue that) { 
    1439                 if( !that.isMutable() ) { 
    1440                     String err = "Left-hand side of assignment must be mutable."; 
    1441                     return Pair.<TypeCheckerResult,Type>make(new TypeCheckerResult(that, TypeError.make(err, that)), Types.BOTTOM); 
    1442                 } 
    1443                 else { 
    1444                     Type lhs_type = that.getIdType().unwrap(); 
    1445                     return Pair.make(checkSubtype(rhs_type, 
    1446                             lhs_type, that, 
    1447                             "Type of right-hand side of assignment, " + rhs_type + ", must be a sub-type of left-hand side, " + lhs_type + "."), 
    1448                             lhs_type); 
    1449                 } 
    1450             } 
    1451  
    1452             @Override 
    1453             public Pair<TypeCheckerResult, Type> forParam(Param that) { 
    1454                             if ( ! NodeUtil.isVarargsParam(that) ) { 
    1455                 if( !NodeUtil.isMutable(that) ) { 
    1456                     String err = "Left-hand side of assignment must be mutable."; 
    1457                     return Pair.<TypeCheckerResult,Type>make(new TypeCheckerResult(that, TypeError.make(err, that)), Types.BOTTOM); 
    1458                 } 
    1459                 else { 
    1460                     Type lhs_type = that.getIdType().unwrap(); 
    1461                     return Pair.make(checkSubtype(rhs_type, 
    1462                             lhs_type, that, 
    1463                             "Type of right-hand side of assignment, " + rhs_type + ", must be a sub-type of left-hand side, " + lhs_type + "."), 
    1464                             lhs_type); 
    1465                 } 
    1466                             } else 
    1467                                 return bug(that, "Varargs parameter should not appear in the left-hand side of an assignment."); 
    1468             } 
    1469  
    1470             @Override 
    1471             public Pair<TypeCheckerResult, Type> forSubscriptExpr(SubscriptExpr that) { 
    1472                 // If there is an op, we must typechecker that as a normal read reference 
    1473                 TypeCheckerResult read_result = recur(that); // only used if opr is SOME 
    1474  
    1475                 // make sure there is a subscript setter for type 
    1476                 // This method is very similar to forSubscriptExprOnly in Typechecker 
    1477                 // except that we must graft the new RHS type onto the end of subs_types 
    1478                 // to see if there is an appropriate setter method. 
    1479                 TypeCheckerResult obj_result = that.getObj().accept(TypeChecker.this); 
    1480                 List<TypeCheckerResult> subs_result = TypeChecker.this.recurOnListOfExpr(that.getSubs()); 
    1481                 // ignore op_result... 
    1482                 List<TypeCheckerResult> staticArgs_result = TypeChecker.this.recurOnListOfStaticArg(that.getStaticArgs()); 
    1483  
    1484                 TypeCheckerResult all_result = 
    1485                     TypeCheckerResult.compose(that, subtypeChecker, obj_result, 
    1486                             TypeCheckerResult.compose(that, subtypeChecker, subs_result), 
    1487                             TypeCheckerResult.compose(that, subtypeChecker, staticArgs_result)); 
    1488  
    1489                 if( obj_result.type().isNone() ) return Pair.<TypeCheckerResult,Type>make(all_result,Types.BOTTOM); 
    1490                 for( TypeCheckerResult r : subs_result ) 
    1491                     if( r.type().isNone() ) return Pair.<TypeCheckerResult,Type>make(all_result,Types.BOTTOM); 
    1492  
    1493                 // get types 
    1494                 Type obj_type = obj_result.type().unwrap(); 
    1495                 List<Type> subs_types = CollectUtil.makeList(IterUtil.map(subs_result, new Lambda<TypeCheckerResult,Type>(){ 
    1496                     public Type value(TypeCheckerResult arg0) { return arg0.type().unwrap(); }})); 
    1497                 // put rhs type on the end 
    1498                 subs_types = Useful.concat(subs_types, Collections.singletonList(rhs_type)); 
    1499  
    1500                 TypeCheckerResult final_result = 
    1501                     TypeChecker.this.subscriptHelper(that, that.getOp(), obj_type, subs_types, that.getStaticArgs()); 
    1502  
    1503                 SubscriptExpr new_node = (SubscriptExpr)read_result.ast(); 
    1504  
    1505                 if(opr.isSome() && read_result.isSuccessful() ) { 
    1506                     return Pair.<TypeCheckerResult,Type>make(TypeCheckerResult.compose(new_node, 
    1507                             read_result.type(), subtypeChecker, read_result, final_result, all_result), Types.BOTTOM); 
    1508                 } 
    1509                 else if( opr.isSome()) { 
    1510                     return Pair.make(TypeCheckerResult.compose(new_node, 
    1511                             read_result.type(), subtypeChecker, read_result, final_result, all_result), read_result.type().unwrap()); 
    1512                 } 
    1513                 else { 
    1514                     return Pair.<TypeCheckerResult,Type>make(TypeCheckerResult.compose(new_node, 
    1515                             read_result.type(), subtypeChecker, final_result, all_result), Types.BOTTOM); 
    1516                 } 
    1517             } 
    1518  
    1519             @Override 
    1520             public Pair<TypeCheckerResult, Type> forVarRef(VarRef that) { 
    1521                 TypeCheckerResult var_result = recur(that); 
    1522                 if( !var_result.isSuccessful() ) return Pair.<TypeCheckerResult, Type>make(var_result, Types.BOTTOM); 
    1523  
    1524                 TypeCheckerResult sub_result = checkSubtype(rhs_type, var_result.type().unwrap(), lhs, 
    1525                         "Type of right-hand side of assignment, " +rhs_type+ ", must be subtype of left-hand side, " + var_result.type() + "."); 
    1526  
    1527                 TypeEnv env = that.getVarId().getApiName().isSome() ? returnTypeEnvForApi(that.getVarId().getApiName().unwrap()) : typeEnv; 
    1528                 Option<BindingLookup> bl = env.binding(that.getVarId()); 
    1529                 if( bl.isNone() ) return bug("Inconsistent results from TypeEnv and typechecking VarRef"); 
    1530  
    1531                 // make sure it's immutable 
    1532                 if( !(bl.unwrap().isMutable()) ) { 
    1533                     String err = "Left-hand side of assignment must be mutable."; 
    1534                     return Pair.<TypeCheckerResult,Type>make(new TypeCheckerResult(that, TypeError.make(err, that)), Types.BOTTOM); 
    1535                 } 
    1536                 else { 
    1537                     return Pair.make(TypeCheckerResult.compose(var_result.ast(), subtypeChecker, sub_result, var_result), var_result.type().unwrap()); 
    1538                 } 
    1539             } 
    1540  
    1541         }); 
    1542  
    1543         final Type arg_type = result_and_arg_type.second(); 
    1544         // Find the arrow type of the opr, if it is some 
    1545         Option<TypeCheckerResult> opr_type = (new NodeDepthFirstVisitor<TypeCheckerResult>() { 
    1546             @Override public TypeCheckerResult forFnRef(FnRef that) { 
    1547                             return TypeChecker.this.recur(that); 
    1548                         } 
    1549             @Override public TypeCheckerResult forOpRef(OpRef that) { 
    1550                             if ( isPostInference(that) ) { 
    1551                                 Type args_type = NodeFactory.makeTupleType(NodeUtil.getSpan(that), 
    1552                                                                            Useful.list(arg_type, rhs_type)); 
    1553                                 return findStaticallyMostApplicableFn(TypeChecker.destructOpOverLoading(that.getOverloadings().unwrap()), 
    1554                                                                       args_type, that, that.getOriginalName()); 
    1555                             } 
    1556  
    1557                             TypeCheckerResult op_result = TypeChecker.this.recur(that); 
    1558                             if( !op_result.isSuccessful() ) return op_result; 
    1559  
    1560                             Option<Pair<Type, ConstraintFormula>> app_result = 
    1561                             TypesUtil.applicationType(subtypeChecker, op_result.type().unwrap(), new ArgList(arg_type, rhs_type), downwardConstraint); 
    1562  
    1563                             if( app_result.isNone() ) { 
    1564                                 String err = "No overloading of " + that.getOriginalName() + " can be found that applies to types " + 
    1565                                     arg_type + " and " + rhs_type + "."; 
    1566                                 return new TypeCheckerResult(that, TypeError.make(err, that)); 
    1567                             } 
    1568                             else { 
    1569                                 TypeCheckerResult app_result_ = new TypeCheckerResult(that, app_result.unwrap().second()); 
    1570                                 return TypeCheckerResult.compose(op_result.ast(), subtypeChecker, app_result_, op_result); 
    1571                             } 
    1572                         } 
    1573                     }).recurOnOptionOfFunctionalRef(opr); 
    1574  
    1575         TypeCheckerResult result = TypeCheckerResult.compose(result_and_arg_type.first().ast(), subtypeChecker, result_and_arg_type.first(), 
    1576                                                                      TypeCheckerResult.compose(result_and_arg_type.first().ast(), subtypeChecker, opr_type)); 
    1577  
    1578         return Pair.<Option<FunctionalRef>,TypeCheckerResult>make((Option<FunctionalRef>)TypeCheckerResult.astFromResult(opr_type), result); 
    1579     } 
    1580  
    1581     /** 
    1582      * An assertion that the type of the given expression should be a tuple type of the given size. 
    1583      * If it is of a different size, an error will be reported. If is not an instance of TupleType, 
    1584      * a tuple of inference variables will be created instead, with the restriction that it must have the 
    1585      * same type as e's type. 
    1586      */ 
    1587     private Pair<List<Type>, TypeCheckerResult> requireTupleType(final Expr e, int size) { 
    1588         final List<Type> inference_var_types = NodeFactory.make_InferenceVarTypes(NodeUtil.getSpan(e), size); // may not be used 
    1589         final TypeCheckerResult e_result = recur(e); 
    1590  
    1591         if( !e_result.isSuccessful() ) 
    1592             return Pair.make(inference_var_types, e_result); 
    1593  
    1594         if( size == 1 ) { 
    1595             return Pair.make(Collections.singletonList(e_result.type().unwrap()), e_result); 
    1596         } 
    1597  
    1598         return e_result.type().unwrap().accept(new TypeAbstractVisitor<Pair<List<Type>, TypeCheckerResult>>() { 
    1599             @Override 
    1600             public Pair<List<Type>, TypeCheckerResult> forTupleType(TupleType that) { 
    1601                 return Pair.make(that.getElements(), e_result); 
    1602             } 
    1603             @Override 
    1604             public Pair<List<Type>, TypeCheckerResult> forType(Type that) { 
    1605                 Type tuple_type = NodeFactory.makeTupleType(NodeUtil.getSpan(that), 
    1606                                                                             inference_var_types); 
    1607                 TypeCheckerResult sub_1 = checkSubtype(tuple_type, that, e); 
    1608                 TypeCheckerResult sub_2 = checkSubtype(that, tuple_type, e); 
    1609                 TypeCheckerResult tcr = TypeCheckerResult.compose(e, subtypeChecker, sub_1, sub_2, e_result); 
    1610                 return Pair.make(inference_var_types, tcr); 
    1611             } 
    1612         }); 
    1613     } 
    1614  
    1615  
    1616     private TypeCheckerResult forAtomic(Expr body, final String errorMsg) { 
    1617         TypeChecker newChecker = new TypeChecker(table, 
    1618                 //staticParamEnv, 
    1619                 typeEnv, 
    1620                 compilationUnit, 
    1621                 subtypeChecker, 
    1622                 labelExitTypes, 
    1623                 postInference, 
    1624                 downwardConstraint) { 
    1625             @Override public TypeCheckerResult forSpawn(Spawn that) { 
    1626                 // Use TypeChecker's forSpawn method, but compose an error onto the result 
    1627                 return TypeCheckerResult.compose( 
    1628                         that, 
    1629                         subtypeChecker, 
    1630                         new TypeCheckerResult(that, 
    1631                                 TypeError.make(errorMsg, 
    1632                                         that)), that.accept(TypeChecker.this)); 
    1633             } 
    1634         }; 
    1635         return body.accept(newChecker); 
    1636     } 
    1637  
    1638     @Override 
    1639     public TypeCheckerResult forAtomicExpr(AtomicExpr that) { 
    1640         TypeCheckerResult expr_result = 
    1641             forAtomic(that.getExpr(), 
    1642                     errorMsg("A 'spawn' expression must not occur inside an 'atomic' expression.")); 
    1643  
    1644         AtomicExpr new_node = ExprFactory.makeAtomicExpr(NodeUtil.getSpan(that), 
    1645                 NodeUtil.isParenthesized(that), 
    1646                 expr_result.type(), 
    1647                 (Expr)expr_result.ast()); 
    1648         return TypeCheckerResult.compose(new_node, expr_result.type(), subtypeChecker, expr_result); 
    1649     } 
    1650  
    1651     @Override 
    1652     public TypeCheckerResult forBigFixity(BigFixity that) { 
    1653         return new TypeCheckerResult(that); 
    1654     } 
    1655  
    1656     @Override 
    1657     public TypeCheckerResult forCaseExpr(CaseExpr thatCaseExpr) { 
    1658         Option<TypeCheckerResult> param_result = this.recurOnOptionOfExpr(thatCaseExpr.getParam()); 
    1659         Option<TypeCheckerResult> compare_result = this.recurOnOptionOfFunctionalRef(thatCaseExpr.getCompare()); 
    1660         TypeCheckerResult equalsOp_result = thatCaseExpr.getEqualsOp().accept(this); 
    1661         TypeCheckerResult inOp_result = thatCaseExpr.getInOp().accept(this); 
    1662         NodeDepthFirstVisitor<Triple<CaseClause, TypeCheckerResult,TypeCheckerResult>> temp = new NodeDepthFirstVisitor<Triple<CaseClause, TypeCheckerResult,TypeCheckerResult>>() { 
    1663             @Override 
    1664             public Triple<CaseClause, TypeCheckerResult, TypeCheckerResult> forCaseClause( 
    1665                     CaseClause that) { 
    1666                 TypeCheckerResult match_result = that.getMatchClause().accept(TypeChecker.this); 
    1667                 TypeCheckerResult body_result = that.getBody().accept(TypeChecker.this); 
    1668                 CaseClause new_node = NodeFactory.makeCaseClause(NodeUtil.getSpan(that), (Expr)match_result.ast(), (Block)body_result.ast(), 
    1669                                                                      that.getOp()); 
    1670                 return Triple.<CaseClause,TypeCheckerResult,TypeCheckerResult>make(new_node, match_result, body_result); 
    1671             } 
    1672         }; 
    1673         List<Triple<CaseClause, TypeCheckerResult,TypeCheckerResult>> clauses_result = temp.recurOnListOfCaseClause(thatCaseExpr.getClauses()); 
    1674         Option<TypeCheckerResult> elseClause_result = recurOnOptionOfBlock(thatCaseExpr.getElseClause()); 
    1675  
    1676         // Checker that clauses all typechecked properly 
    1677         for(Triple<CaseClause, TypeCheckerResult,TypeCheckerResult> clause_result: clauses_result){ 
    1678             if(clause_result.second().type().isNone() || clause_result.third().type().isNone()) { 
    1679                 return TypeCheckerResult.compose(thatCaseExpr, subtypeChecker, 
    1680                         TypeCheckerResult.compose(thatCaseExpr, subtypeChecker, CollectUtil.makeList(IterUtil.tripleSeconds(clauses_result))), 
    1681                         TypeCheckerResult.compose(thatCaseExpr, subtypeChecker, CollectUtil.makeList(IterUtil.tripleThirds(clauses_result)))); 
    1682             } 
    1683         } 
    1684  
    1685         // Check that compare typechecked, if it exists 
    1686         if( compare_result.isSome()) { 
    1687             if(compare_result.unwrap().type().isNone()){ 
    1688                 return TypeCheckerResult.compose(thatCaseExpr, subtypeChecker, compare_result.unwrap()); 
    1689             } 
    1690         } 
    1691         // Check elseClause 
    1692         if(elseClause_result.isSome()){ 
    1693             if(elseClause_result.unwrap().type().isNone()){ 
    1694                 return TypeCheckerResult.compose(thatCaseExpr, subtypeChecker, elseClause_result.unwrap()); 
    1695             } 
    1696         } 
    1697         // Check if we are dealing with a normal case (i.e. not an extremum) 
    1698         if (thatCaseExpr.getParam().isSome()) { 
    1699             if(param_result.unwrap().type().isNone()){ 
    1700                 return TypeCheckerResult.compose(thatCaseExpr, subtypeChecker, param_result.unwrap()); 
    1701             } 
    1702  
    1703             if(equalsOp_result.type().isNone() || inOp_result.type().isNone()){ 
    1704                 return bug("Equals or In does not have a type"); 
    1705             } 
    1706  
    1707             return forCaseExprNormal(thatCaseExpr); 
    1708         } else { 
    1709             return forExtremumOnly(thatCaseExpr, compare_result.unwrap(), clauses_result); 
    1710         } 
    1711     } 
    1712  
    1713     // Handle regular (non-extremum) case expressions 
    1714     private TypeCheckerResult forCaseExprNormal(CaseExpr that) { 
    1715         Option<TypeCheckerResult> else_result_ = recurOnOptionOfBlock(that.getElseClause()); 
    1716         Option<TypeCheckerResult> param_result_ = recurOnOptionOfExpr(that.getParam()); 
    1717         Option<TypeCheckerResult> compare_result_ = recurOnOptionOfFunctionalRef(that.getCompare()); 
    1718         TypeCheckerResult equals_result = recur(that.getEqualsOp()); 
    1719         TypeCheckerResult in_result = recur(that.getInOp()); 
    1720  
    1721         // Check all of these subexpressions 
    1722         if( (else_result_.isSome() && !else_result_.unwrap().isSuccessful()) || (param_result_.isSome() && !param_result_.unwrap().isSuccessful()) || 
    1723                 (compare_result_.isSome() && !compare_result_.unwrap().isSuccessful()) || !equals_result.isSuccessful() || !in_result.isSuccessful() ) { 
    1724             TypeCheckerResult.compose(that, subtypeChecker, equals_result, in_result, 
    1725                     TypeCheckerResult.compose(that, subtypeChecker, else_result_, param_result_, compare_result_)); 
    1726         } 
    1727  
    1728         List<TypeCheckerResult> clause_results = new ArrayList<TypeCheckerResult>(that.getClauses().size()); 
    1729         List<Type> clause_types = new ArrayList<Type>(that.getClauses().size()); 
    1730  
    1731         for( CaseClause clause : that.getClauses() ) { 
    1732             Type param_type = param_result_.unwrap().type().unwrap(); // assured by the fact that we are caseExprNormal 
    1733  
    1734             if( postInference ) { 
    1735                 // after inference, the case clause had better have the op field set 
    1736                             if( clause.getOp().isNone() ) 
    1737                                     return bug("All case clauses should be rewritten to reflect the chosen compare op."); 
    1738  
    1739                 Pair<Type, TypeCheckerResult> p = for_CaseClauseGetType(clause, param_result_); 
    1740                 clause_results.add(p.second()); 
    1741                 clause_types.add(p.first()); 
    1742             } 
    1743             else { 
    1744                 // during inference, we'll try to apply the given compare op (if there is one) and otherwise try 
    1745                 // equals and in. We will set the op field with a chosen opr. 
    1746                 Pair<Type, TypeCheckerResult> p = forCaseClauseRewriteAndGetType(clause, param_result_, compare_result_, equals_result, in_result); 
    1747                 clause_results.add(p.second()); 
    1748                 clause_types.add(p.first()); 
    1749             } 
    1750         } 
    1751  
    1752         // Also, do else block if necessary 
    1753         if( else_result_.isSome() ) { 
    1754             clause_types.add(else_result_.unwrap().type().unwrap()); 
    1755         } 
    1756  
    1757         Type result_type = NodeFactory.makeIntersectionType(CollectUtil.asSet(clause_types)); 
    1758         CaseExpr new_node = ExprFactory.makeCaseExpr(NodeUtil.getSpan(that), 
    1759                 NodeUtil.isParenthesized(that), 
    1760                 some(result_type), 
    1761                 (Option<Expr>)TypeCheckerResult.astFromResult(param_result_), 
    1762                 (Option<FunctionalRef>)TypeCheckerResult.astFromResult(compare_result_), 
    1763                 (FunctionalRef)equals_result.ast(), 
    1764                 (FunctionalRef)in_result.ast(), 
    1765                 (List<CaseClause>)TypeCheckerResult.astFromResults(clause_results), 
    1766                 (Option<Block>)TypeCheckerResult.astFromResult(else_result_)); 
    1767         TypeCheckerResult result = TypeCheckerResult.compose(new_node, subtypeChecker, equals_result, in_result, 
    1768                 TypeCheckerResult.compose(new_node, subtypeChecker, clause_results), 
    1769                 TypeCheckerResult.compose(new_node, subtypeChecker, param_result_, compare_result_, else_result_)); 
    1770  
    1771         // The application of operators (IN, EQUALS) could cause Inference Vars to be introduced 
    1772         TypeCheckerResult successful = new TypeCheckerResult(that); 
    1773         if( postInference && TypesUtil.containsInferenceVarTypes(new_node) ) { 
    1774             Pair<Boolean,Node> temp1 = TypesUtil.closeConstraints(new_node, result); 
    1775             new_node = (CaseExpr)temp1.second(); 
    1776             Pair<Boolean,Node> temp2 = TypesUtil.closeConstraints(result_type, result); 
    1777             result_type = (Type)temp2.second(); 
    1778             if(!temp1.first() || !temp2.first()){ 
    1779                 String err = "No overloading of " + (that.getCompare().isSome()? that.getCompare().unwrap() + "." : that.getEqualsOp() + " or " + that.getInOp() + "."); 
    1780                 successful = new TypeCheckerResult(that, TypeError.make(err,that)); 
    1781             } 
    1782         } 
    1783         return TypeCheckerResult.compose(new_node, result_type, subtypeChecker, result); 
    1784     } 
    1785  
    1786     /** 
    1787      * Typecheck the clause, using one of the ops (compare, equals, or in), return the type of the right-hand side block, and 
    1788      * rewrite the CaseClause to set the op field. All TypeCheckerResults must contain types, and must contain the AST type 
    1789      * that is reflected by their name. 
    1790      */ 
    1791     private Pair<Type, TypeCheckerResult> forCaseClauseRewriteAndGetType(CaseClause clause, Option<TypeCheckerResult> param_result_, 
    1792             Option<TypeCheckerResult> compare_result_, TypeCheckerResult equals_result, TypeCheckerResult in_result) { 
    1793         TypeCheckerResult match_result = recur(clause.getMatchClause()); 
    1794         TypeCheckerResult block_result = recur(clause.getBody()); 
    1795  
    1796         // make sure subexpressions were well-typed 
    1797         if( !match_result.isSuccessful() || !block_result.isSuccessful() ) 
    1798             return Pair.<Type,TypeCheckerResult>make(Types.BOTTOM, TypeCheckerResult.compose(clause, subtypeChecker, match_result, block_result)); 
    1799  
    1800         Type match_type = match_result.type().unwrap(); 
    1801         Type block_type = block_result.type().unwrap(); 
    1802         FunctionalRef chosen_op; 
    1803         Option<Pair<Type, ConstraintFormula>> application_result; 
    1804         Type param_type = param_result_.unwrap().type().unwrap(); 
    1805         ArgList args = new ArgList(param_type, match_type); 
    1806  
    1807         // If compare is some, we use that operator 
    1808         if( compare_result_.isSome() ) { 
    1809             chosen_op = (FunctionalRef)compare_result_.unwrap().ast(); 
    1810             Type compare_type = compare_result_.unwrap().type().unwrap(); 
    1811             application_result = TypesUtil.applicationType(subtypeChecker, compare_type, args, downwardConstraint); 
    1812         } 
    1813         else { 
    1814             // Check both = and IN operators 
    1815             // we first want to do <: generator test. 
    1816             // If both are sat, we use =, if only gen_subtype_c is sat, we use IN 
    1817             ConstraintFormula gen_subtype_c = 
    1818                 subtypeChecker.subtype(match_type, Types.makeGeneratorType(NodeFactory.make_InferenceVarType(NodeUtil.getSpan(clause)))); 
    1819             ConstraintFormula gen_subtype_p = 
    1820                 subtypeChecker.subtype(param_type, Types.makeGeneratorType(NodeFactory.make_InferenceVarType(NodeUtil.getSpan(clause)))); 
    1821  
    1822             if( gen_subtype_c.isSatisfiable() && !gen_subtype_p.isSatisfiable() ) { 
    1823                 // Implicit IN 
    1824                 chosen_op = (FunctionalRef)in_result.ast(); 
    1825                 Type in_type = in_result.type().unwrap(); 
    1826                 application_result = TypesUtil.applicationType(subtypeChecker, in_type, args, downwardConstraint); 
    1827             } 
    1828             else { 
    1829                 // Implicit = 
    1830                 chosen_op = (FunctionalRef)equals_result.ast(); 
    1831                 Type equals_type = equals_result.type().unwrap(); 
    1832                 application_result = TypesUtil.applicationType(subtypeChecker, equals_type, args, downwardConstraint); 
    1833             } 
    1834         } 
    1835  
    1836         if( application_result.isNone() ) { 
    1837             // error 
    1838             String err = "No overloading of the operator " + chosen_op + " could be found for arguments of type " + 
    1839             param_type + " (Param Type)  and " + match_type + " (Match Type)."; 
    1840             TypeCheckerResult e_r = new TypeCheckerResult(clause, TypeError.make(err, clause)); 
    1841             return Pair.<Type,TypeCheckerResult>make(block_type, TypeCheckerResult.compose(clause, subtypeChecker, e_r, match_result, block_result)); 
    1842         } 
    1843         else { 
    1844             CaseClause new_node = NodeFactory.makeCaseClause(NodeUtil.getSpan(clause), 
    1845                                                              (Expr)match_result.ast(), 
    1846                                                              (Block)block_result.ast(), 
    1847                                                              Option.<FunctionalRef>some(chosen_op)); 
    1848             TypeCheckerResult app_result = new TypeCheckerResult(new_node, application_result.unwrap().second()); 
    1849             Type app_type = application_result.unwrap().first(); 
    1850             // We still must ensure the type of the application is a Boolean 
    1851             TypeCheckerResult bool_result = checkSubtype(app_type, Types.BOOLEAN, new_node, 
    1852                     "Result of application of " + chosen_op + " to param and match expression must have type boolean, but had type " + app_type + "."); 
    1853             return Pair.make(block_type, TypeCheckerResult.compose(new_node, subtypeChecker, bool_result, app_result, match_result, block_result)); 
    1854         } 
    1855     } 
    1856     /** 
    1857          * pointInference pass 
    1858      * Typecheck the clause AND return the type of the right-hand side. 
    1859      */ 
    1860     private Pair<Type, TypeCheckerResult> for_CaseClauseGetType(CaseClause clause, Option<TypeCheckerResult> param_result_) { 
    1861             // after inference, the case clause had better have the op field set 
    1862             if( clause.getOp().isNone() ) 
    1863                 return bug("All case clauses should be rewritten to reflect the chosen compare op."); 
    1864  
    1865             FunctionalRef op = clause.getOp().unwrap(); 
    1866  
    1867         TypeCheckerResult match_result = recur(clause.getMatchClause()); 
    1868         TypeCheckerResult block_result = recur(clause.getBody()); 
    1869  
    1870         // make sure subexpressions were well-typed 
    1871         if( !match_result.isSuccessful() || !block_result.isSuccessful() ) 
    1872             return Pair.<Type,TypeCheckerResult>make(Types.BOTTOM, TypeCheckerResult.compose(clause, subtypeChecker, match_result, block_result)); 
    1873  
    1874         Type match_type = match_result.type().unwrap(); 
    1875         Type block_type = block_result.type().unwrap(); 
    1876         Type param_type = param_result_.unwrap().type().unwrap(); 
    1877  
    1878         if( isPostInference(op) ) { 
    1879             // Our operator is an overloading, so we should find the statically most applicable one and rewrite 
    1880             Type arg_type = NodeFactory.makeTupleType(NodeUtil.getSpan(clause), 
    1881                                                                   Useful.list(param_type, match_type)); 
    1882             TypeCheckerResult app_result_1 = 
    1883                             findStaticallyMostApplicableFn(destructOpOverLoading(op.getOverloadings().unwrap()), 
    1884                                                            arg_type, op, op.getOriginalName()); 
    1885  
    1886             if( app_result_1.isSuccessful() ) { 
    1887                 Type arrow_type = app_result_1.type().unwrap(); 
    1888                 Option<Pair<Type, ConstraintFormula>> app_result_2 = 
    1889                     TypesUtil.applicationType(subtypeChecker, arrow_type, new ArgList(param_type, match_type), downwardConstraint); 
    1890  
    1891                 if( app_result_2.isSome() ) { 
    1892                     CaseClause new_node = NodeFactory.makeCaseClause(NodeUtil.getSpan(clause), 
    1893                                                                              (Expr)match_result.ast(), 
    1894                                                                              (Block)block_result.ast(), 
    1895                                                                              Option.<FunctionalRef>some((FunctionalRef)app_result_1.ast())); 
    1896                     TypeCheckerResult app_result_3 = new TypeCheckerResult(new_node, app_result_2.unwrap().second()); 
    1897                     Type app_type = app_result_2.unwrap().first(); 
    1898                     // We still must ensure the type of the application is a Boolean 
    1899                     TypeCheckerResult bool_result = checkSubtype(app_type, Types.BOOLEAN, new_node, 
    1900                                                                                      "Result of application of " + op + " to param and match expression must have type boolean, but had type " + app_type + "."); 
    1901                     return Pair.make(block_type, TypeCheckerResult.compose(new_node, subtypeChecker, bool_result, app_result_3, match_result, block_result)); 
    1902                 } 
    1903                 else { 
    1904                     // should be impossible, unless applicationType and findStaticallyMostApplicable don't agree... 
    1905                     return bug("applicationType and findStaticallyMostApplicable do not agree to function applicability. " + clause); 
    1906                 } 
    1907             } 
    1908             else { 
    1909                 return Pair.make(block_type, TypeCheckerResult.compose(clause, subtypeChecker, app_result_1, match_result, block_result, param_result_.unwrap())); 
    1910             } 
    1911         } 
    1912         else { 
    1913             // no overloading, so just do the normal thing 
    1914                     TypeCheckerResult op_result = recur(op); 
    1915             if( !op_result.isSuccessful() ) return Pair.make(block_type, TypeCheckerResult.compose(clause, subtypeChecker, op_result)); 
    1916             Option<Pair<Type, ConstraintFormula>> app_result_1 = 
    1917                 TypesUtil.applicationType(subtypeChecker, op_result.type().unwrap(), new ArgList(param_type, match_type), downwardConstraint); 
    1918             if( app_result_1.isSome() ) { 
    1919                 CaseClause new_node = NodeFactory.makeCaseClause(NodeUtil.getSpan(clause), 
    1920                                                                      (Expr)match_result.ast(), 
    1921                                                                      (Block)block_result.ast(), 
    1922                                                                      Option.<FunctionalRef>some((FunctionalRef)op_result.ast())); 
    1923                 TypeCheckerResult app_result_2 = new TypeCheckerResult(new_node, app_result_1.unwrap().second()); 
    1924                 Type app_type = app_result_1.unwrap().first(); 
    1925                 // We still must ensure the type of the application is a Boolean 
    1926                 TypeCheckerResult bool_result = checkSubtype(app_type, Types.BOOLEAN, new_node, 
    1927                                                                              "Result of application of " + op + " to param and match expression must have type boolean, but had type " + app_type + "."); 
    1928                 return Pair.make(block_type, TypeCheckerResult.compose(new_node, subtypeChecker, bool_result, app_result_2, match_result, block_result)); 
    1929             } 
    1930             else { 
    1931                 // error 
    1932                             String err = "No overloading of the operator " + op + " could be found for arguments of type " + 
    1933                 param_type + " (Param Type)  and " + match_type + " (Match Type)."; 
    1934                 TypeCheckerResult e_r = new TypeCheckerResult(clause, TypeError.make(err, clause)); 
    1935                 return Pair.<Type,TypeCheckerResult>make(block_type, TypeCheckerResult.compose(clause, subtypeChecker, e_r, match_result, block_result)); 
    1936             } 
    1937         } 
    1938     } 
    1939  
    1940  
    1941     @Override 
    1942     public TypeCheckerResult forCatch(Catch that) { 
    1943         // We have to pass the name down so it can be bound to each exn type in turn 
    1944         Id bound_name = that.getName(); 
    1945         List<TypeCheckerResult> clause_results = 
    1946             recurOnCatchClausesWithIdToBind(that.getClauses(),bound_name); 
    1947         // Gather all the types of the catch clauses 
    1948         List<Type> clause_types = new ArrayList<Type>(clause_results.size()); 
    1949         for( TypeCheckerResult r : clause_results ) { 
    1950             if( r.type().isSome() ) 
    1951                 clause_types.add(r.type().unwrap()); 
    1952         } 
    1953         // resulting type is the join of those types 
    1954         Type result_type = subtypeChecker.join(clause_types); 
    1955  
    1956         Catch new_node = NodeFactory.makeCatch(NodeUtil.getSpan(that), 
    1957                 that.getName(), 
    1958                 (List<CatchClause>)TypeCheckerResult.astFromResults(clause_results)); 
    1959  
    1960         return TypeCheckerResult.compose(new_node, result_type, 
    1961                 subtypeChecker, clause_results).addNodeTypeEnvEntry(new_node, typeEnv); 
    1962     } 
    1963  
    1964     /** 
    1965      * Given the CatchClause and an Id, the Id will be bound to the exception type that the catch 
    1966      * clause declares to catch, and then its body will be type-checked. 
    1967      */ 
    1968     private TypeCheckerResult forCatchClauseWithIdToBind(CatchClause that, 
    1969             Id id_to_bind) { 
    1970         TypeCheckerResult match_result = that.getMatchType().accept(this); 
    1971         // type must be an exception 
    1972         TypeCheckerResult is_exn_result = checkSubtype(that.getMatchType(), Types.EXCEPTION, that.getMatchType(), 
    1973                 "Catch clauses must catch sub-types of Exception, but " + that.getMatchType() + " is not."); 
    1974  
    1975         // bind id and check the body 
    1976         LValue lval = NodeFactory.makeLValue(id_to_bind, that.getMatchType()); 
    1977         TypeChecker extend_tc = this.extend(Collections.singletonList(lval)); 
    1978         TypeCheckerResult body_result = that.getBody().accept(extend_tc); 
    1979  
    1980         // result has body type 
    1981         Option<Type> result_type = body_result.type(); 
    1982  
    1983         CatchClause new_node = NodeFactory.makeCatchClause(NodeUtil.getSpan(that), 
    1984                 (BaseType)match_result.ast(), 
    1985                 (Block)body_result.ast()); 
    1986  
    1987         return TypeCheckerResult.compose(new_node, result_type, subtypeChecker, match_result, is_exn_result, body_result); 
    1988     } 
    1989  
    1990     @Override 
    1991     public TypeCheckerResult forChainExpr(ChainExpr that) { 
    1992         TypeCheckerResult first_result = that.getFirst().accept(this); 
    1993         List<TypeCheckerResult> bool_exprs = new ArrayList<TypeCheckerResult>(that.getLinks().size()); 
    1994         List<TypeCheckerResult> link_result = new ArrayList<TypeCheckerResult>(that.getLinks().size()); 
    1995         List<TypeCheckerResult> temps_result = new ArrayList<TypeCheckerResult>(that.getLinks().size()); 
    1996