return items.StackItem(msilType(type));
return items.StackItem(mtype);
    private Item primitiveOp(Tree left, Symbol opSym, Tree right, MSILType resType)    {	assert primitives.isPrimitive(opSym);	Primitive op = primitives.getPrimitive(opSym);	// treat some special cases	switch (op) {	case BOX:	    return invokeMethod(opSym, new Tree[]{right}, resType, false); 	case CONCAT:	    genLoad(left, MSILType.OBJECT);	    genLoad(right, MSILType.OBJECT);	    code.Emit(OpCodes.Call, tc.CONCAT_OBJECT_OBJECT);	    return items.StackItem(MSILType.STRING);	case ADD:	    if (tc.getType(right.type) == tc.STRING) {		log("primaryOp().ADD: string concat!");		genLoad(left, MSILType.OBJECT);		genLoad(right, MSILType.OBJECT);		code.Emit(OpCodes.Call, tc.CONCAT_OBJECT_OBJECT);		return items.StackItem(MSILType.STRING);	    }	    break;	case IS:	    genLoad(left, MSILType.OBJECT);	    final Type type = tc.getType(right.type);	    code.Emit(OpCodes.Isinst, type);	    return mkCond(items.StackItem(msilType(type)));	case AS:	    Item i = genLoad(left, MSILType.OBJECT);	    final Type type = tc.getType(right.type);	    if (!i.type.isType(type) && type != tc.OBJECT) {		code.Emit(OpCodes.Castclass, type);	    }	    return items.StackItem(msilType(type));	case SYNCHRONIZED:	    // TODO: reuse temporary local variable whenever possible	    LocalBuilder tmp = code.DeclareLocal(tc.OBJECT);	    genLoad(left, MSILType.OBJECT);	    code.Emit(OpCodes.Stloc, tmp);	    code.Emit(OpCodes.Ldloc, tmp);	    code.Emit(OpCodes.Call, tc.MONITOR_ENTER);	    genLoad(right, MSILType.OBJECT);	    code.Emit(OpCodes.Ldloc, tmp);	    code.Emit(OpCodes.Call, tc.MONITOR_EXIT);	    return items.StackItem(MSILType.OBJECT);	}	Item iLeft = null;	MSILType tleft = msilType(left);	switch (left) {	case Apply(Tree fun , Tree[] args):	    Primitive p = primitives.getPrimitive(fun.symbol());	    switch (p) {	    case BOX:		assert args.length == 1;		iLeft = gen(args[0], msilType(args[0]));		break;	    }	    break;	default:	    iLeft = gen(left, tleft);	}	switch (op) {	case THROW:	    load(iLeft);	    code.Emit(OpCodes.Throw);	    code.Emit(OpCodes.Ldnull);	    return items.StackItem(MSILType.OBJECT);	case POS: return load(coerce(iLeft, resType));	case NEG:	    iLeft = load(coerce(iLeft, resType));	    code.Emit(OpCodes.Neg);	    return iLeft;	case NOT:	    iLeft = load(coerce(iLeft, resType));	    code.Emit(OpCodes.Not);	    return iLeft;	case ZNOT:	    return negate(mkCond(iLeft));	case ZOR:	    Item.CondItem lcond = mkCond(iLeft), rcond = null;	    Chain success = lcond.success, failure = lcond.failure;	    switch (lcond.test) {	    case True:		return lcond;	    case False: 		return mkCond(gen(right, MSILType.BOOL));	    case And(Test t):		success = (success != null) ?		    success : new Chain(code.DefineLabel(), null);		branch(negate(lcond.test), success);		resolve(failure);		failure = null;		break;	    default:		success = (success != null) ?		    success : new Chain(code.DefineLabel(), null);		branch(negate(lcond.test), success);	    }	    rcond = mkCond((gen(right, MSILType.BOOL)));	    rcond = items.CondItem(Test.Or(rcond.test),				   merge(success, rcond.success),				   merge(failure, rcond.failure));	    return rcond;	case ZAND:	    Item.CondItem lcond = mkCond(iLeft), rcond = null;	    Chain success = lcond.success, failure = lcond.failure;	    switch (lcond.test) {	    case False:		return lcond;	    case True: 		return mkCond(gen(right, MSILType.BOOL));	    case Or(Test t):		failure = (failure != null) ?		    failure : new Chain(code.DefineLabel(), null);		branch(lcond.test, failure);		resolve(success);		success = null;		break;	    default:		failure = (failure != null) ?		    failure : new Chain(code.DefineLabel(), null);		branch(lcond.test, failure);	    }	    rcond = mkCond(gen(right, MSILType.BOOL));	    rcond = items.CondItem(Test.And(rcond.test),				   merge(success, rcond.success),				   merge(failure, rcond.failure));	    return rcond;	}	MSILType toType = arithmCoercion(iLeft.type, primitiveType(right.type));	load(coerce(iLeft, toType));	genLoad(right, toType);	Item res = null;	switch (op) {	case ADD: code.Emit(OpCodes.Add); res = items.StackItem(toType); break;	case SUB: code.Emit(OpCodes.Sub); res = items.StackItem(toType); break;	case MUL: code.Emit(OpCodes.Mul); res = items.StackItem(toType); break;	case DIV: code.Emit(OpCodes.Div); res = items.StackItem(toType); break;	case MOD: code.Emit(OpCodes.Rem); res = items.StackItem(toType); break;	case OR:  code.Emit(OpCodes.Or);  res = items.StackItem(toType); break;	case XOR: code.Emit(OpCodes.Xor); res = items.StackItem(toType); break;	case AND: code.Emit(OpCodes.And); res = items.StackItem(toType); break;	case LSL: code.Emit(OpCodes.Shl); res = items.StackItem(toType); break;	case LSR: code.Emit(OpCodes.Shr); res = items.StackItem(toType); break;	case ASR: code.Emit(OpCodes.Shr_Un); res = items.StackItem(toType); break;	case EQ:	    res =  items.CondItem(Test.Binary(Test.EQ, toType), null, null);	    break;	case NE:	    res = items.CondItem(Test.Binary(Test.NE, toType), null, null);	    break;	case LT:	    res = items.CondItem(Test.Binary(Test.LT_IS, toType), null, null);	    break;	case LE:	    res = items.CondItem(Test.Binary(Test.LE_IS, toType), null, null);	    break;	case GT:	    res = items.CondItem(Test.Binary(Test.GT_IS, toType), null, null);	    break;	case GE:	    res = items.CondItem(Test.Binary(Test.GE_IS, toType), null, null);	    break;	default:	    throw new ApplicationError(Debug.show(op));	}	return coerce(res, resType);    }