genLoadQualifier(ctx, tree);
genLoadQualifier(ctx, tree, true);
    protected JType genLoad(Context ctx, Tree tree, JType expectedType) {        startCodeForTree(ctx, tree);        JType generatedType = null;        Symbol sym = tree.symbol();        switch (tree) {        case LabelDef(_, Tree.Ident[] params, Tree rhs): {            JCode.Label label = ctx.code.newLabel();            label.anchorToNext();            ctx.labels.put(sym, new Pair(label, params));            generatedType = genLoad(ctx, rhs, expectedType);            ctx.labels.remove(sym);        } break;        case Block(Tree[] stats): {            int statsNum = stats.length;            for (int i = 0; i < statsNum - 1; ++i)                gen(ctx, stats[i]);            if (statsNum == 0)                maybeGenLoadUnit(ctx, expectedType);            else                genLoad(ctx, stats[stats.length - 1], expectedType);            generatedType = expectedType;        } break;        case Typed(Tree expr, _):            genLoad(ctx, expr, expectedType);            generatedType = expectedType;            break;        case New(Tree.Template templ): {            assert templ.body.length == 0;            assert templ.parents.length == 1;            String className = javaName(tree.type.symbol());            ctx.code.emitNEW(className);            ctx.code.emitDUP();            gen(ctx, templ.parents[0]);            generatedType = new JObjectType(className);        } break;        case Apply(TypeApply(Tree fun, Tree[] args), _): {            genLoadQualifier(ctx, fun);            JType type = typeStoJ(args[0].type);            if (fun.symbol() == defs.IS) {                ctx.code.emitINSTANCEOF((JReferenceType)type);                generatedType = JType.BOOLEAN;            } else if (fun.symbol() == defs.AS) {                ctx.code.emitCHECKCAST((JReferenceType)type);                generatedType = type;            } else                global.fail("unexpected type application");        } break;        case Apply(Tree fun, Tree[] args): {            Symbol funSym = fun.symbol();            if (funSym.isLabel()) {                Pair/*<Label, Tree[]>*/ labelAndIdents =                    (Pair)ctx.labels.get(funSym);                assert labelAndIdents != null : Debug.show(funSym);                JMethodType funType = (JMethodType)typeStoJ(funSym.info());                JCode.Label label = (JCode.Label)labelAndIdents.fst;                Tree[] idents = (Tree[])labelAndIdents.snd;                assert idents.length == args.length;                for (int i = 0; i < args.length; ++i)                    genLoad(ctx, args[i], typeStoJ(args[i].type));                for (int i = idents.length; i > 0; --i)                    genStoreEpilogue(ctx, idents[i-1]);                ctx.code.emitGOTO(label);                generatedType = funType.getReturnType();            } else if (isKnownPrimitive(funSym)) {                Primitive prim = prims.getPrimitive(funSym);                switch (prim) {                case CONCAT:                    genStringConcatenation(ctx, liftStringConcatenations(tree));                    generatedType = JAVA_LANG_STRING_T;                    break;                case POS: case NEG:                case ADD: case SUB: case MUL: case DIV: case MOD:                case NOT: case OR : case XOR: case AND:                case LSL: case LSR: case ASR:                    Tree[] allArgs = extractPrimitiveArgs((Tree.Apply)tree);                    JType resType = typeStoJ(tree.type);                    genArithPrim(ctx, prim, allArgs, resType, expectedType);                    generatedType = resType;                    break;                case ID:                case EQ: case NE: case LT: case LE: case GE: case GT:                case ZNOT: case ZOR: case ZAND:                    JCode.Label falseLabel = ctx.code.newLabel();                    JCode.Label afterLabel = ctx.code.newLabel();                    genCond(ctx, tree, falseLabel, false);                    ctx.code.emitICONST_1();                    ctx.code.emitGOTO(afterLabel);                    falseLabel.anchorToNext();                    ctx.code.emitICONST_0();                    afterLabel.anchorToNext();                    generatedType = JType.BOOLEAN;                    break;                case THROW:                    assert args.length == 0;                    genThrow(ctx, ((Tree.Select)fun).qualifier);                    // We pretend that we generated something of the                    // expected type, to avoid trying to generate                    // bogus conversions.                    generatedType = expectedType;                    break;                case NEW_ZARRAY : case NEW_BARRAY : case NEW_SARRAY :                case NEW_CARRAY : case NEW_IARRAY : case NEW_LARRAY :                case NEW_FARRAY : case NEW_DARRAY :                    assert args.length == 1;                    genArrayCreate(ctx, prim, args[0]);                    generatedType = JAVA_LANG_OBJECT_T; // TODO refine                    break;                case ZARRAY_SET : case BARRAY_SET : case SARRAY_SET :                case CARRAY_SET : case IARRAY_SET : case LARRAY_SET :                case FARRAY_SET : case DARRAY_SET : case OARRAY_SET :                    assert args.length == 3;                    genArrayUpdate(ctx, args[0], args[1], args[2]);                    generatedType = JType.VOID;                    break;                case ZARRAY_GET : case BARRAY_GET : case SARRAY_GET :                case CARRAY_GET : case IARRAY_GET : case LARRAY_GET :                case FARRAY_GET : case DARRAY_GET : case OARRAY_GET :                    assert args.length == 2 : "get - " + args.length;                    genArrayAccess(ctx, args[0], args[1]);                    generatedType = getArrayElementType(args[0]);                    break;                case ZARRAY_LENGTH : case BARRAY_LENGTH : case SARRAY_LENGTH :                case CARRAY_LENGTH : case IARRAY_LENGTH : case LARRAY_LENGTH :                case FARRAY_LENGTH : case DARRAY_LENGTH : case OARRAY_LENGTH :                    assert args.length == 1 : args.length;                    genArrayLength(ctx, args[0]);                    generatedType = JType.INT;                    break;                case AS_UVALUE :                    assert args.length == 0;                    gen(ctx, ((Tree.Select)fun).qualifier);                    generatedType = JType.VOID;                    break;                default:                    throw Debug.abort("unknown primitive ", prim);                }            } else {                JMethodType funType = (JMethodType)typeStoJ(funSym.info());                JType[] argTypes = funType.getArgumentTypes();                boolean isConstrCall = (funSym.name == CONSTRUCTOR_NAME);                boolean isSuperCall;                switch (fun) {                case Select(Super(_, _), _): isSuperCall = true; break;                default: isSuperCall = false; break;                }                boolean isStatic = isStaticMember(funSym);                if (!(isStatic || (isConstrCall && !isSuperCall)))                    genLoadQualifier(ctx, fun);                for (int i = 0; i < args.length; ++i)                    genLoad(ctx, args[i], argTypes[i]);                String clsName = isSuperCall                    ? ctx.clazz.getSuperclassName()                    : javaName(funSym.owner());                String mthName = funSym.name.toString();                funSym.owner().info(); // [HACK] ensure that flags are                                       // transformed.                // [HACK] in reality isSuperCall should never be true                // is the owner is an interface, but this is a quick                // fix before ExpandMixins is fixed.                if (funSym.owner().isInterface() && !isSuperCall)                    ctx.code.emitINVOKEINTERFACE(clsName, mthName, funType);                else {                    if (isConstrCall || isSuperCall) {                        ctx.code.emitINVOKESPECIAL(clsName, mthName, funType);                        if (isConstrCall && isSuperCall && ctx.isModuleClass) {                            // Initialise module instance field ASAP                            ctx.code.emitALOAD_0();                            ctx.code.emitPUTSTATIC(ctx.clazz.getName(),                                                   MODULE_INSTANCE_FIELD_NAME,                                                   ctx.clazz.getType());                        }                    } else if (isStatic)                        ctx.code.emitINVOKESTATIC(clsName, mthName, funType);                    else                        ctx.code.emitINVOKEVIRTUAL(clsName, mthName, funType);                }                generatedType = funType.getReturnType();            }        } break;        case Ident(Name name): {            JType type = typeStoJ(sym.info());            if (sym.isModule())                generatedType = genLoadModule(ctx, sym);            else if (sym == defs.NULL) {                ctx.code.emitACONST_NULL();                generatedType = expectedType;            } else if (sym.owner().isClass()) {                ctx.code.emitALOAD_0();                ctx.code.emitGETFIELD(ctx.clazz.getName(), name.toString(), type);                generatedType = type;            } else {                assert ctx.locals.containsKey(sym)                    : Debug.show(sym) + " not in " + ctx.locals;                int index = ((Integer)(ctx.locals.get(sym))).intValue();                ctx.code.emitLOAD(index, type);                generatedType = type;            }        } break;        case Select(Tree qualifier, Name selector): {            if (sym.isModule())                generatedType = genLoadModule(ctx, sym);            else {                JType fieldType = typeStoJ(sym.info());                String className = javaName(sym.owner());                String fieldName = selector.toString();                if (isStaticMember(sym))                    ctx.code.emitGETSTATIC(className, fieldName, fieldType);                else {                    genLoadQualifier(ctx, tree);                    ctx.code.emitGETFIELD(className, fieldName, fieldType);                }                generatedType = fieldType;            }        } break;        case Assign(Tree lhs, Tree rhs): {            genStorePrologue(ctx, lhs);            genLoad(ctx, rhs, typeStoJ(lhs.symbol().info()));            genStoreEpilogue(ctx, lhs);            generatedType = JType.VOID;        } break;        case If(Tree cond, Tree thenp, Tree elsep): {            JType finalType = typeStoJ(tree.type);            JCode.Label elseLabel = ctx.code.newLabel();            genCond(ctx, cond, elseLabel, false);            genLoad(ctx, thenp, finalType);            JCode.Label afterLabel = ctx.code.newLabel();            ctx.code.emitGOTO(afterLabel);            elseLabel.anchorToNext();            if (elsep == Tree.Empty)                maybeGenLoadUnit(ctx, finalType);            else                genLoad(ctx, elsep, finalType);            afterLabel.anchorToNext();            generatedType = finalType;        } break;        case Switch(Tree test, int[] tags, Tree[] bodies, Tree otherwise): {            JCode.Label[] labels = ctx.code.newLabels(bodies.length);            JCode.Label defaultLabel = ctx.code.newLabel();            JCode.Label afterLabel = ctx.code.newLabel();            genLoad(ctx, test, JType.INT);            ctx.code.emitSWITCH(tags, labels, defaultLabel, 0.9);            for (int i = 0; i < bodies.length; ++i) {                labels[i].anchorToNext();                genLoad(ctx, bodies[i], expectedType);                ctx.code.emitGOTO(afterLabel);            }            defaultLabel.anchorToNext();            genLoad(ctx, otherwise, expectedType);            afterLabel.anchorToNext();            generatedType = expectedType;        } break;        case This(_):        case Super(_, _):            ctx.code.emitALOAD_0();            generatedType = JAVA_LANG_OBJECT_T;            break;        case Literal(Object value):            if (value instanceof Integer) {                generatedType = JType.INT;                ctx.code.emitPUSH((Integer)value);            } else if (value instanceof Long) {                generatedType = JType.LONG;                ctx.code.emitPUSH((Long)value);            } else if (value instanceof Float) {                generatedType = JType.FLOAT;                ctx.code.emitPUSH((Float)value);            } else if (value instanceof Double) {                generatedType = JType.DOUBLE;                ctx.code.emitPUSH((Double)value);            } else if (value instanceof Character) {                generatedType = JType.CHAR;                ctx.code.emitPUSH((Character)value);            } else if (value instanceof String) {                generatedType = JAVA_LANG_STRING_T;                ctx.code.emitPUSH((String)value);            } else if (value instanceof Boolean) {                generatedType = JType.BOOLEAN;                ctx.code.emitPUSH((Boolean)value);            } else                throw global.fail("unknown literal " + value);            break;        case Empty:        case AbsTypeDef(_, _, _, _):        case AliasTypeDef(_, _, _, _):        case TypeApply(_, _):        case FunType(_, _):        case CompoundType(_, _):        case AppliedType(_,_):            generatedType = JType.VOID;            break;        case Sequence(_):        case ModuleDef(_,_,_,_):        case PatDef(_,_,_):        case Import(_, _):        case CaseDef(_, _, _):        case Visitor(_):        case Function(_, _):            throw global.fail("unexpected node", tree);        case Bad():            throw global.fail("bad tree");        default:            throw global.fail("unknown node", tree);        }        // Pop unneeded result from stack, or widen it if needed.        if (expectedType == JType.VOID && generatedType != JType.VOID) {            if (generatedType == JType.LONG || generatedType == JType.DOUBLE)                ctx.code.emitPOP2();            else                ctx.code.emitPOP();        } else if (! (expectedType == JType.VOID                      || generatedType == expectedType                      || generatedType.isReferenceType()))            genWidenConversion(ctx, generatedType, expectedType);        endCodeForTree(ctx, tree);        return expectedType;    }