* possibly work. Typically this means either the statically resolvable
* arg type is incompatible with the target type, or the target type was
* globally uninstantiable. We handle this cast by throwing a
* ClassCastException, unless the argument is null.
*/
JMethod method = program.getIndexedMethod("Cast.throwClassCastExceptionUnlessNull");
/*
* Override the type of the magic method with the null type.
*/
JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method,
program.getTypeNull());
call.addArg(expr);
replaceExpr = call;
} else if (toType instanceof JReferenceType) {
JExpression curExpr = expr;
JReferenceType refType = (JReferenceType) toType;
JReferenceType argType = (JReferenceType) expr.getType();
if (program.typeOracle.canTriviallyCast(argType, refType)) {
// just remove the cast
replaceExpr = curExpr;
} else {
JMethod method;
boolean isJsoCast = program.isJavaScriptObject(toType);
if (isJsoCast) {
// A cast to a concrete JSO subtype
method = program.getIndexedMethod("Cast.dynamicCastJso");
} else if (program.typeOracle.getSingleJsoImpls().containsKey(toType)) {
// An interface that should succeed when the object is a JSO
method = program.getIndexedMethod("Cast.dynamicCastAllowJso");
} else {
// A regular cast
method = program.getIndexedMethod("Cast.dynamicCast");
}
// override the type of the called method with the target cast type
JMethodCall call = new JMethodCall(x.getSourceInfo(), null, method,
toType);
call.addArg(curExpr);
if (!isJsoCast) {
JIntLiteral qId = program.getLiteralInt(queryIds.get(refType));
call.addArg(qId);
}
replaceExpr = call;
}
} else {
/*
* See JLS 5.1.3: if a cast narrows from one type to another, we must
* call a narrowing conversion function. EXCEPTION: we currently have no
* way to narrow double to float, so don't bother.
*/
JPrimitiveType tByte = program.getTypePrimitiveByte();
JPrimitiveType tChar = program.getTypePrimitiveChar();
JPrimitiveType tShort = program.getTypePrimitiveShort();
JPrimitiveType tInt = program.getTypePrimitiveInt();
JPrimitiveType tLong = program.getTypePrimitiveLong();
JPrimitiveType tFloat = program.getTypePrimitiveFloat();
JPrimitiveType tDouble = program.getTypePrimitiveDouble();
JType fromType = expr.getType();
String methodName = null;
if (tLong == fromType && tLong != toType) {
if (tByte == toType || tShort == toType || tChar == toType) {
/*
* We need a double call here, one to convert long->int, and another
* one to narrow. Construct the inner call here and fall through to
* do the narrowing conversion.
*/
JMethod castMethod = program.getIndexedMethod("LongLib.toInt");
JMethodCall call = new JMethodCall(x.getSourceInfo(), null,
castMethod);
call.addArg(expr);
expr = call;
fromType = tInt;
} else if (tInt == toType) {
methodName = "LongLib.toInt";
} else if (tFloat == toType || tDouble == toType) {
methodName = "LongLib.toDouble";
}
}
if (toType == tLong && fromType != tLong) {
// Longs get special treatment.
if (tByte == fromType || tShort == fromType || tChar == fromType
|| tInt == fromType) {
methodName = "LongLib.fromInt";
} else if (tFloat == fromType || tDouble == fromType) {
methodName = "LongLib.fromDouble";
}
} else if (tByte == fromType) {
if (tChar == toType) {
methodName = "Cast.narrow_" + toType.getName();
}
} else if (tShort == fromType) {
if (tByte == toType || tChar == toType) {
methodName = "Cast.narrow_" + toType.getName();
}
} else if (tChar == fromType) {
if (tByte == toType || tShort == toType) {
methodName = "Cast.narrow_" + toType.getName();
}
} else if (tInt == fromType) {
if (tByte == toType || tShort == toType || tChar == toType) {
methodName = "Cast.narrow_" + toType.getName();
}
} else if (tFloat == fromType || tDouble == fromType) {
if (tByte == toType || tShort == toType || tChar == toType
|| tInt == toType) {
methodName = "Cast.round_" + toType.getName();
}
}
if (methodName != null) {
JMethod castMethod = program.getIndexedMethod(methodName);
JMethodCall call = new JMethodCall(x.getSourceInfo(), null,
castMethod, toType);
call.addArg(expr);
replaceExpr = call;
} else {