Introduce concept of 'weak' cast.

Use weak casts to maintain proper typing within methods during various operations on IR. At generation level, ignore weak casts, except for Wasm GC BE, which turns weak casts into platform casts.
This commit is contained in:
Alexey Andreev 2024-08-18 18:47:04 +02:00
parent 8b52741e04
commit a97e6574ac
33 changed files with 84 additions and 136 deletions

View File

@ -21,6 +21,7 @@ import org.teavm.model.ValueType;
public class CastExpr extends Expr {
private Expr value;
private ValueType target;
private boolean weak;
public Expr getValue() {
return value;
@ -38,6 +39,14 @@ public class CastExpr extends Expr {
this.target = target;
}
public boolean isWeak() {
return weak;
}
public void setWeak(boolean weak) {
this.weak = weak;
}
@Override
public void acceptVisitor(ExprVisitor visitor) {
visitor.visit(this);
@ -48,6 +57,7 @@ public class CastExpr extends Expr {
CastExpr copy = new CastExpr();
copy.value = value.clone(cache);
copy.target = target;
copy.weak = weak;
return copy;
}
}

View File

@ -214,6 +214,7 @@ class StatementGenerator implements InstructionVisitor {
expr.setVariableIndex(insn.getReceiver().getIndex());
expr.setValue(Expr.var(insn.getValue().getIndex()));
expr.setTarget(insn.getTargetType());
expr.setWeak(insn.isWeak());
assign(expr, insn.getReceiver());
}

View File

@ -1056,6 +1056,11 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
@Override
public void visit(CastExpr expr) {
if (expr.isWeak()) {
expr.getValue().acceptVisitor(this);
return;
}
if (expr.getTarget() instanceof ValueType.Object) {
String className = ((ValueType.Object) expr.getTarget()).getClassName();
if (!context.getCharacteristics().isManaged(className)) {

View File

@ -878,7 +878,7 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
@Override
public void visit(CastExpr expr) {
if (context.isStrict()) {
if (context.isStrict() && !expr.isWeak()) {
if (expr.getLocation() != null) {
pushLocation(expr.getLocation());
}

View File

@ -20,19 +20,15 @@ import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.analysis.BaseTypeInference;
import org.teavm.model.instructions.InvocationType;
public class PreciseTypeInference extends BaseTypeInference<PreciseValueType> {
public static final PreciseValueType OBJECT_TYPE = new PreciseValueType(ValueType.object("java.lang.Object"),
false);
private ClassHierarchy hierarchy;
private WasmGCMethodReturnTypes returnTypes;
public PreciseTypeInference(Program program, MethodReference reference, ClassHierarchy hierarchy,
WasmGCMethodReturnTypes returnTypes) {
public PreciseTypeInference(Program program, MethodReference reference, ClassHierarchy hierarchy) {
super(program, reference);
this.hierarchy = hierarchy;
this.returnTypes = returnTypes;
}
@Override
@ -108,14 +104,6 @@ public class PreciseTypeInference extends BaseTypeInference<PreciseValueType> {
return new PreciseValueType(ValueType.arrayOf(preciseValueType.valueType), false);
}
@Override
protected PreciseValueType methodReturnType(InvocationType invocationType, MethodReference methodRef) {
if (invocationType == InvocationType.SPECIAL) {
return new PreciseValueType(returnTypes.returnTypeOf(methodRef), false);
}
return super.methodReturnType(invocationType, methodRef);
}
@Override
protected PreciseValueType arrayUnwrapType(PreciseValueType type) {
return new PreciseValueType(type.valueType, true);

View File

@ -1,64 +0,0 @@
/*
* Copyright 2024 Alexey Andreev.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.backend.wasm.gc;
import java.util.HashMap;
import java.util.Map;
import org.teavm.dependency.DependencyInfo;
import org.teavm.model.ClassHierarchy;
import org.teavm.model.MethodReference;
import org.teavm.model.ValueType;
public class WasmGCMethodReturnTypes {
private DependencyInfo dependencyInfo;
private ClassHierarchy hierarchy;
private Map<MethodReference, ValueType> cache = new HashMap<>();
public WasmGCMethodReturnTypes(DependencyInfo dependencyInfo, ClassHierarchy hierarchy) {
this.dependencyInfo = dependencyInfo;
this.hierarchy = hierarchy;
}
public ValueType returnTypeOf(MethodReference reference) {
return cache.computeIfAbsent(reference, this::calculateReturnType);
}
private ValueType calculateReturnType(MethodReference reference) {
if (!(reference.getReturnType() instanceof ValueType.Object)) {
return reference.getReturnType();
}
var method = dependencyInfo.getMethod(reference);
if (method == null) {
return reference.getReturnType();
}
var types = method.getResult().getTypes();
if (types.length == 0) {
return reference.getReturnType();
}
var type = hierarchy.getClassSource().get(types[0]);
if (type == null) {
return reference.getReturnType();
}
for (var i = 1; i < types.length; ++i) {
var otherType = hierarchy.getClassSource().get(types[i]);
if (otherType == null) {
return reference.getReturnType();
}
type = hierarchy.getClassSource().get(WasmGCUtil.findCommonSuperclass(hierarchy, type, otherType));
}
return ValueType.object(type.getName());
}
}

View File

@ -23,11 +23,9 @@ import org.teavm.model.util.VariableCategoryProvider;
public class WasmGCVariableCategoryProvider implements VariableCategoryProvider {
private ClassHierarchy hierarchy;
private PreciseTypeInference inference;
private WasmGCMethodReturnTypes returnTypes;
public WasmGCVariableCategoryProvider(ClassHierarchy hierarchy, WasmGCMethodReturnTypes returnTypes) {
public WasmGCVariableCategoryProvider(ClassHierarchy hierarchy) {
this.hierarchy = hierarchy;
this.returnTypes = returnTypes;
}
public PreciseTypeInference getTypeInference() {
@ -36,7 +34,7 @@ public class WasmGCVariableCategoryProvider implements VariableCategoryProvider
@Override
public Object[] getCategories(Program program, MethodReference method) {
inference = new PreciseTypeInference(program, method, hierarchy, returnTypes);
inference = new PreciseTypeInference(program, method, hierarchy);
inference.setPhisSkipped(true);
inference.setBackPropagation(true);
var result = new Object[program.variableCount()];

View File

@ -1170,6 +1170,11 @@ public abstract class BaseWasmGenerationVisitor implements StatementVisitor, Exp
@Override
public void visit(CastExpr expr) {
if (expr.isWeak()) {
acceptWithType(expr.getValue(), expr.getTarget());
result = generateCast(result, mapType(expr.getTarget()));
return;
}
var block = new WasmBlock(false);
var wasmTargetType = mapType(expr.getTarget());
block.setType(wasmTargetType);

View File

@ -19,7 +19,6 @@ import java.util.List;
import java.util.function.Predicate;
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
import org.teavm.backend.wasm.generate.WasmNameProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassGenerator;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
@ -47,7 +46,6 @@ public class WasmGCDeclarationsGenerator {
public final WasmFunctionTypes functionTypes;
private final WasmGCClassGenerator classGenerator;
private final WasmGCMethodGenerator methodGenerator;
private final WasmGCMethodReturnTypes returnTypes;
public WasmGCDeclarationsGenerator(
WasmModule module,
@ -64,7 +62,6 @@ public class WasmGCDeclarationsGenerator {
var virtualTables = createVirtualTableProvider(classes, virtualMethods);
functionTypes = new WasmFunctionTypes(module);
var names = new WasmNameProvider();
returnTypes = new WasmGCMethodReturnTypes(dependencyInfo, hierarchy);
methodGenerator = new WasmGCMethodGenerator(
module,
hierarchy,
@ -74,7 +71,6 @@ public class WasmGCDeclarationsGenerator {
functionTypes,
names,
diagnostics,
returnTypes,
customGenerators,
intrinsics
);

View File

@ -23,7 +23,6 @@ import java.util.Map;
import java.util.Set;
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
import org.teavm.backend.wasm.generate.common.methods.BaseWasmGenerationContext;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
@ -57,7 +56,6 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
private WasmGCSupertypeFunctionProvider supertypeFunctions;
private WasmGCCustomGeneratorProvider customGenerators;
private WasmGCIntrinsicProvider intrinsics;
private WasmGCMethodReturnTypes returnTypes;
private WasmFunction npeMethod;
private WasmFunction aaiobeMethod;
private WasmFunction cceMethod;
@ -70,8 +68,7 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
ClassHierarchy hierarchy, BaseWasmFunctionRepository functions,
WasmGCSupertypeFunctionProvider supertypeFunctions, WasmGCClassInfoProvider classInfoProvider,
WasmGCStandardClasses standardClasses, WasmGCStringProvider strings,
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics,
WasmGCMethodReturnTypes returnTypes) {
WasmGCCustomGeneratorProvider customGenerators, WasmGCIntrinsicProvider intrinsics) {
this.module = module;
this.virtualTables = virtualTables;
this.typeMapper = typeMapper;
@ -85,7 +82,6 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
this.strings = strings;
this.customGenerators = customGenerators;
this.intrinsics = intrinsics;
this.returnTypes = returnTypes;
}
public WasmGCClassInfoProvider classInfoProvider() {
@ -186,10 +182,6 @@ public class WasmGCGenerationContext implements BaseWasmGenerationContext {
return intrinsics;
}
public WasmGCMethodReturnTypes returnTypes() {
return returnTypes;
}
public Collection<String> getInterfaceImplementors(String className) {
if (interfaceImplementors == null) {
fillInterfaceImplementors();

View File

@ -481,7 +481,7 @@ public class WasmGCGenerationVisitor extends BaseWasmGenerationVisitor {
@Override
protected WasmExpression forceType(WasmExpression expression, ValueType type) {
return forceType(expression, mapType(context.returnTypes().returnTypeOf(currentMethod)));
return forceType(expression, mapType(currentMethod.getReturnType()));
}
private WasmExpression forceType(WasmExpression expression, WasmType expectedType) {

View File

@ -25,7 +25,6 @@ import org.teavm.ast.decompilation.Decompiler;
import org.teavm.backend.lowlevel.generate.NameProvider;
import org.teavm.backend.wasm.BaseWasmFunctionRepository;
import org.teavm.backend.wasm.WasmFunctionTypes;
import org.teavm.backend.wasm.gc.WasmGCMethodReturnTypes;
import org.teavm.backend.wasm.gc.WasmGCVariableCategoryProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCClassInfoProvider;
import org.teavm.backend.wasm.generate.gc.classes.WasmGCStandardClasses;
@ -78,7 +77,6 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
private WasmGCClassInfoProvider classInfoProvider;
private WasmGCStandardClasses standardClasses;
private WasmGCStringProvider strings;
private WasmGCMethodReturnTypes returnTypes;
public WasmGCMethodGenerator(
WasmModule module,
@ -89,7 +87,6 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
WasmFunctionTypes functionTypes,
NameProvider names,
Diagnostics diagnostics,
WasmGCMethodReturnTypes returnTypes,
WasmGCCustomGeneratorProvider customGenerators,
WasmGCIntrinsicProvider intrinsics
) {
@ -101,7 +98,6 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
this.functionTypes = functionTypes;
this.names = names;
this.diagnostics = diagnostics;
this.returnTypes = returnTypes;
this.customGenerators = customGenerators;
this.intrinsics = intrinsics;
}
@ -146,7 +142,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
}
private WasmFunction createStaticFunction(MethodReference methodReference) {
var returnType = typeMapper.mapType(returnTypes.returnTypeOf(methodReference));
var returnType = typeMapper.mapType(methodReference.getReturnType());
var parameterTypes = new WasmType[methodReference.parameterCount()];
for (var i = 0; i < parameterTypes.length; ++i) {
parameterTypes[i] = typeMapper.mapType(methodReference.parameterType(i));
@ -173,7 +169,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
}
private WasmFunction createInstanceFunction(MethodReference methodReference) {
var returnType = typeMapper.mapType(returnTypes.returnTypeOf(methodReference));
var returnType = typeMapper.mapType(methodReference.getReturnType());
var parameterTypes = new WasmType[methodReference.parameterCount() + 1];
parameterTypes[0] = typeMapper.mapType(ValueType.object(methodReference.getClassName()));
for (var i = 0; i < methodReference.parameterCount(); ++i) {
@ -213,7 +209,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
private void generateRegularMethodBody(MethodHolder method, WasmFunction function) {
var decompiler = getDecompiler();
var categoryProvider = new WasmGCVariableCategoryProvider(hierarchy, returnTypes);
var categoryProvider = new WasmGCVariableCategoryProvider(hierarchy);
var allocator = new RegisterAllocator(categoryProvider);
allocator.allocateRegisters(method.getReference(), method.getProgram(), friendlyToDebugger);
var ast = decompiler.decompileRegular(method);
@ -302,8 +298,7 @@ public class WasmGCMethodGenerator implements BaseWasmFunctionRepository {
standardClasses,
strings,
customGenerators,
intrinsics,
returnTypes
intrinsics
);
}
return context;

View File

@ -714,6 +714,7 @@ public class AstIO {
output.writeUnsigned(23);
output.writeUnsigned(symbolTable.lookup(expr.getTarget().toString()));
writeExpr(expr.getValue());
output.writeUnsigned(expr.isWeak() ? 1 : 0);
} catch (IOException e) {
throw new IOExceptionWrapper(e);
}
@ -1106,6 +1107,7 @@ public class AstIO {
expr.setLocation(lastReadLocation);
expr.setTarget(ValueType.parse(symbolTable.at(input.readUnsigned())));
expr.setValue(readExpr(input));
expr.setWeak(input.readUnsigned() != 0);
return expr;
}
case 24: {

View File

@ -451,12 +451,13 @@ public class ProgramIO {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
try {
output.writeUnsigned(25);
output.writeUnsigned(receiver.getIndex());
output.writeUnsigned(symbolTable.lookup(targetType.toString()));
output.writeUnsigned(value.getIndex());
output.writeUnsigned(weak ? 1 : 0);
} catch (IOException e) {
throw new IOExceptionWrapper(e);
}
@ -988,6 +989,7 @@ public class ProgramIO {
insn.setReceiver(program.variableAt(input.readUnsigned()));
insn.setTargetType(parseValueType(symbolTable.at(input.readUnsigned())));
insn.setValue(program.variableAt(input.readUnsigned()));
insn.setWeak(input.readUnsigned() != 0);
return insn;
}
case 26: {

View File

@ -228,12 +228,14 @@ abstract class AbstractInstructionAnalyzer extends AbstractInstructionReader {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
String className = extractClassName(targetType);
if (className != null) {
getAnalyzer().linkClass(className);
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
if (!weak) {
String className = extractClassName(targetType);
if (className != null) {
getAnalyzer().linkClass(className);
}
getAnalyzer().linkClass("java.lang.ClassCastException");
}
getAnalyzer().linkClass("java.lang.ClassCastException");
}
@Override

View File

@ -95,7 +95,7 @@ class ClassClosureAnalyzer extends AbstractInstructionReader {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
build(targetType);
}

View File

@ -143,7 +143,7 @@ public class DataFlowGraphBuilder extends AbstractInstructionReader {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
builder.addEdge(value.getIndex(), receiver.getIndex());
}

View File

@ -221,9 +221,11 @@ class DependencyGraphBuilder {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
super.cast(receiver, value, targetType);
currentExceptionConsumer.consume(dependencyAnalyzer.getType("java.lang.ClassCastException"));
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
super.cast(receiver, value, targetType, weak);
if (!weak) {
currentExceptionConsumer.consume(dependencyAnalyzer.getType("java.lang.ClassCastException"));
}
DependencyNode valueNode = nodes[value.getIndex()];
DependencyNode receiverNode = nodes[receiver.getIndex()];
ClassReaderSource classSource = dependencyAnalyzer.getClassSource();

View File

@ -83,7 +83,7 @@ public class InstructionReadVisitor implements InstructionVisitor {
@Override
public void visit(CastInstruction insn) {
reader.cast(insn.getReceiver(), insn.getValue(), insn.getTargetType());
reader.cast(insn.getReceiver(), insn.getValue(), insn.getTargetType(), insn.isWeak());
}
@Override

View File

@ -340,7 +340,7 @@ public class Interpreter {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean cast) {
variables[receiver.getIndex()] = asJvmClass(targetType).cast(variables[value.getIndex()]);
}

View File

@ -77,7 +77,7 @@ public class AbstractInstructionReader implements InstructionReader {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
}
@Override

View File

@ -23,6 +23,7 @@ public class CastInstruction extends Instruction {
private Variable value;
private Variable receiver;
private ValueType targetType;
private boolean weak;
public Variable getValue() {
return value;
@ -48,6 +49,14 @@ public class CastInstruction extends Instruction {
this.targetType = targetType;
}
public boolean isWeak() {
return weak;
}
public void setWeak(boolean weak) {
this.weak = weak;
}
@Override
public void acceptVisitor(InstructionVisitor visitor) {
visitor.visit(this);

View File

@ -44,7 +44,7 @@ public interface InstructionReader {
void assign(VariableReader receiver, VariableReader assignee);
void cast(VariableReader receiver, VariableReader value, ValueType targetType);
void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak);
void cast(VariableReader receiver, VariableReader value, NumericOperandType sourceType,
NumericOperandType targetType);

View File

@ -43,9 +43,10 @@ public final class ExceptionHandlingUtil {
|| insn instanceof ConstructArrayInstruction || insn instanceof ConstructMultiArrayInstruction
|| insn instanceof CloneArrayInstruction || insn instanceof RaiseInstruction
|| insn instanceof MonitorEnterInstruction || insn instanceof MonitorExitInstruction
|| insn instanceof NullCheckInstruction || insn instanceof BoundCheckInstruction
|| insn instanceof CastInstruction) {
|| insn instanceof NullCheckInstruction || insn instanceof BoundCheckInstruction) {
return true;
} else if (insn instanceof CastInstruction) {
return !((CastInstruction) insn).isWeak();
} else if (insn instanceof InvokeInstruction) {
return isManagedMethodCall(characteristics, ((InvokeInstruction) insn).getMethod());
}

View File

@ -93,7 +93,7 @@ public class NativePointerFinder {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
assignmentGraph.addEdge(value.getIndex(), receiver.getIndex());
}

View File

@ -31,7 +31,6 @@ import org.teavm.model.MethodHolder;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.CastInstruction;
import org.teavm.model.instructions.InvocationType;
import org.teavm.model.instructions.InvokeInstruction;
@ -172,11 +171,7 @@ public class Devirtualization {
}
System.out.println();
}
AssignInstruction assign = new AssignInstruction();
assign.setAssignee(cast.getValue());
assign.setReceiver(cast.getReceiver());
assign.setLocation(cast.getLocation());
cast.replace(assign);
cast.setWeak(true);
eliminatedCasts++;
}
}

View File

@ -570,7 +570,8 @@ public class GlobalValueNumbering implements MethodOptimization {
int a = map[insn.getValue().getIndex()];
int p = replaceMap[insn.getValue().getIndex()];
insn.setValue(program.variableAt(p));
bind(insn.getReceiver().getIndex(), "@" + a + "::" + insn.getTargetType());
var operator = insn.isWeak() ? ":::" : "::";
bind(insn.getReceiver().getIndex(), "@" + a + operator + insn.getTargetType());
}
@Override

View File

@ -240,8 +240,12 @@ class InstructionStringifier implements InstructionReader {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
appendLocalVar(receiver).append(" := cast ").appendLocalVar(value).append(" to ")
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
appendLocalVar(receiver).append(" := ");
if (weak) {
append("weak ");
}
append("cast ").appendLocalVar(value).append(" to ")
.escapeIdentifierIfNeeded(targetType.toString());
}

View File

@ -208,11 +208,12 @@ public class InstructionCopyReader implements InstructionReader {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
CastInstruction insnCopy = new CastInstruction();
insnCopy.setValue(copyVar(value));
insnCopy.setReceiver(copyVar(receiver));
insnCopy.setTargetType(targetType);
insnCopy.setWeak(weak);
copy = insnCopy;
copy.setLocation(location);
}

View File

@ -296,7 +296,7 @@ public class TypeInferer {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
types[receiver.getIndex()] = convert(targetType);
}

View File

@ -465,6 +465,9 @@ class JSClassProcessor {
}
private boolean processCast(CastInstruction cast, CallLocation location) {
if (cast.isWeak()) {
return false;
}
if (!(cast.getTargetType() instanceof ValueType.Object)) {
cast.setTargetType(processType(cast.getTargetType()));
return false;

View File

@ -607,7 +607,7 @@ public class CompositeMethodGenerator {
}
@Override
public void cast(VariableReader receiver, VariableReader value, ValueType targetType) {
public void cast(VariableReader receiver, VariableReader value, ValueType targetType, boolean weak) {
CastInstruction insn = new CastInstruction();
insn.setTargetType(targetType);
insn.setValue(var(value));

View File

@ -77,7 +77,7 @@ class ResourceProgramTransformer {
}
private void removeCastToResource(CastInstruction cast) {
if (hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) {
if (!cast.isWeak() && hierarchy.isSuperType(RESOURCE, cast.getTargetType(), false)) {
AssignInstruction assign = new AssignInstruction();
assign.setReceiver(cast.getReceiver());
assign.setAssignee(cast.getValue());