private void typeConvertEnd(final Type from, final Type to,
                                    boolean castPreferred) {
            Class<?> fromNat = from.getNaturalClass();
            Class<?> toNat = to.getNaturalClass();

            if (fromNat.isArray() && toNat.isArray()) {
                if (fromNat != toNat) {
                    convertArray(from, to);
                }
                return;
            }

            if (from.isPrimitive()) {
                if (to.isPrimitive()) {
                    mBuilder.convert(makeDesc(from), makeDesc(to));
                    return;
                }
                else {
                    // Assume using object peer for primitive type.
                    Class<?> fromObj = from.getObjectClass();
                    Class<?> toObj = to.getObjectClass();

                    if (fromObj == toObj) {
                        if (fromObj == Boolean.class) {
                            TypeDesc td = makeDesc(Boolean.class);

                            Label falseLabel = mBuilder.createLabel();
                            Label endLabel = mBuilder.createLabel();
                            mBuilder.ifZeroComparisonBranch(falseLabel, "==");
                            mBuilder.loadStaticField("java.lang.Boolean",
                                                     "TRUE", td);
                            mBuilder.branch(endLabel);
                            falseLabel.setLocation();
                            mBuilder.loadStaticField("java.lang.Boolean",
                                                     "FALSE", td);
                            endLabel.setLocation();
                        }
                        else if (fromObj == Integer.class) {
                            mBuilder.invokeStatic("openmarker.trove.util.IntegerFactory",
                                                  "toInteger",
                                                  makeDesc(Integer.class),
                                                  cIntParam);
                        }
                        else {
                            TypeDesc[] param = new TypeDesc[1];
                            param[0] = makeDesc(from);
                            mBuilder.invokeConstructor(toObj.getName(), param);
                        }
                        return;
                    }
                }
            }
            else {
                if (to.isPrimitive()) {
                    // Assume using primitive peer for object.
                    if (Number.class.isAssignableFrom(from.getObjectClass()) &&
                        Number.class.isAssignableFrom(to.getObjectClass())) {

                        String methodName = null;
                        if (toNat == int.class) {
                            methodName = "intValue";
                        }
                        else if (toNat == float.class) {
                            methodName = "floatValue";
                        }
                        else if (toNat == long.class) {
                            methodName = "longValue";
                        }
                        else if (toNat == double.class) {
                            methodName = "doubleValue";
                        }
                        else if (toNat == byte.class) {
                            methodName = "byteValue";
                        }
                        else if (toNat == short.class) {
                            methodName = "shortValue";
                        }

                        if (methodName != null) {
                            mBuilder.invokeVirtual("java.lang.Number",
                                                   methodName,
                                                   makeDesc(toNat));
                            return;
                        }
                    }
                    else if (from.getObjectClass() == Boolean.class &&
                             toNat == boolean.class) {

                        mBuilder.invokeVirtual("java.lang.Boolean",
                                               "booleanValue",
                                               makeDesc(toNat));
                        return;
                    }
                    else if (from.getObjectClass() == Character.class &&
                             toNat == char.class) {

                        mBuilder.invokeVirtual("java.lang.Character",
                                               "charValue",
                                               makeDesc(toNat));
                        return;
                    }
                }
                else {
                    if (Number.class.isAssignableFrom(fromNat) &&
                        Number.class.isAssignableFrom(toNat)) {

                        if (fromNat == toNat) {
                            return;
                        }

                        mBuilder.loadStaticField(toNat.getName(), "TYPE",
                                                 makeDesc(Class.class));

                        Method method = getMethod(
                            WrapperTypeConversionUtil.class, "convert",
                            Number.class, Class.class
                        );

                        mBuilder.invoke(method);
                        mBuilder.checkCast(makeDesc(toNat));
                        return;

                    }
                }
            }

            boolean convertStringToNonNull =
                from.isNullable() && to.isNonNull() &&
                String.class.isAssignableFrom(fromNat) &&
                String.class.isAssignableFrom(toNat);

            if (!convertStringToNonNull && toNat.isAssignableFrom(fromNat)) {
                // Do nothing at all for upcast.
                return;
            }

            boolean canCast = fromNat.isAssignableFrom(toNat);
            boolean canConvertToString = toNat.isAssignableFrom(String.class);

            if (canConvertToString && (!canCast || !castPreferred)) {
                // String conversion.
                Method converter = stringConversionMethod(from);

                if (String.class.isAssignableFrom(fromNat)) {
                    // Converting from a String to a non-null String.
                    // Test against null before calling converter.

                    // TODO: if I can detect if a local variable is currently
                    // on the top of the stack, then I can use that instead of
                    // doing dup operations.

                    mBuilder.dup();
                    Label nonNullLabel = mBuilder.createLabel();
                    mBuilder.ifNullBranch(nonNullLabel, false);

                    if (!Modifier.isStatic(converter.getModifiers())) {
                        // Push instance of Context onto stack and
                        // swap it into the correct place.
                        generateContext();
                        mBuilder.swap();
                    }
                    mBuilder.invoke(converter);

                    nonNullLabel.setLocation();
                }
                else if (to.isNullable() &&
                         (from.isNullable() ||
                          fromNat.isAssignableFrom(String.class))) {
                    // Converting to a nullable String from a nullable object
                    // or an object that might already be a string, so perform
                    // special logic.

                    Label castLabel = mBuilder.createLabel();

                    // TODO: if I can detect if a local variable is currently
                    // on the top of the stack, then I can use that instead of
                    // doing dup operations.

                    if (from.isNullable()) {
                        mBuilder.dup();
                        mBuilder.ifNullBranch(castLabel, true);
                    }

                    if (fromNat.isAssignableFrom(String.class)) {
                        mBuilder.dup();
                        mBuilder.instanceOf(TypeDesc.STRING);
                        mBuilder.ifZeroComparisonBranch(castLabel, "!=");
                    }

                    if (!Modifier.isStatic(converter.getModifiers())) {
                        // Push instance of Context onto stack and
                        // swap it into the correct place.
                        generateContext();
                        mBuilder.swap();
                    }
                    mBuilder.invoke(converter);
                    Label continueLabel = mBuilder.createLabel();
                    mBuilder.branch(continueLabel);

                    castLabel.setLocation();
                    mBuilder.checkCast(TypeDesc.STRING);

                    continueLabel.setLocation();
                }
                else {
                    mBuilder.invoke(converter);
                }
                return;
            }
            else if (canCast) {
                if (from != Type.NULL_TYPE) {
                    mBuilder.checkCast(makeDesc(toNat));
                }
                return;
            }

            typeError(from, to);
        }