Compare commits

...

11 Commits

Author SHA1 Message Date
Mikhail Bogdanov
b7e110b0ab Checkcast. Returns 2020-07-10 09:00:14 +02:00
Mikhail Bogdanov
5e4fc125cf Checkcast. Properly process generic properties 2020-07-09 20:41:44 +02:00
Mikhail Bogdanov
bee2ce7b35 Checkcast. Properly process generic properties 2020-07-09 17:05:14 +02:00
Mikhail Bogdanov
66135abc83 ~ 2020-07-09 16:41:48 +02:00
Mikhail Bogdanov
8e7585a3e1 Don't cast lambda parameters 2020-07-09 08:21:06 +02:00
Mikhail Bogdanov
b403256c89 more tests 2020-07-08 15:10:56 +02:00
Mikhail Bogdanov
df465794d5 more implicit casts 2020-07-08 14:26:34 +02:00
Mikhail Bogdanov
da9bf7514d Avoid casts on function calls Mikhail Bogdanov Yesterday 20:16 2020-07-08 12:58:47 +02:00
Mikhail Bogdanov
161123b2cb JVM_IR. Avoid casts on function calls 2020-07-08 12:58:47 +02:00
Mikhail Bogdanov
86c26beed5 Support ir 2020-07-08 10:51:58 +02:00
Mikhail Bogdanov
f41527d30b Generate less checkcasts 2020-07-08 10:51:58 +02:00
44 changed files with 1065 additions and 120 deletions

View File

@@ -1038,7 +1038,12 @@ public class AsmUtil {
return new StackValue(stackValue.type, stackValue.kotlinType) {
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
Type innerType = stackValue.type;
KotlinType innerKotlinType = stackValue.kotlinType;
stackValue.put(innerType, innerKotlinType, v);

View File

@@ -48,7 +48,12 @@ abstract class SafeCallFusedWithPrimitiveEqualityBase(
v.mark(endLabel)
}
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
val falseLabel = Label()
val endLabel = Label()

View File

@@ -22,7 +22,12 @@ open class BranchedValue(
val opcode: Int
) : StackValue(Type.BOOLEAN_TYPE) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
val branchJumpLabel = Label()
condJump(branchJumpLabel, v, true)
val endLabel = Label()
@@ -66,7 +71,12 @@ open class BranchedValue(
}
}
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
v.iconst(1)
coerceTo(type, kotlinType, v)
}
@@ -89,7 +99,12 @@ open class BranchedValue(
}
}
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
v.iconst(0)
coerceTo(type, kotlinType, v)
}
@@ -172,7 +187,12 @@ class Invert(val condition: BranchedValue) : BranchedValue(condition, null, Type
class CondJump(val condition: BranchedValue, op: Int) : BranchedValue(condition, null, Type.BOOLEAN_TYPE, op) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
throw UnsupportedOperationException("Use condJump instead")
}

View File

@@ -68,7 +68,7 @@ interface CallGenerator {
}
val value = codegen.gen(argumentExpression)
value.put(parameterType.type, parameterType.kotlinType, v)
value.put(parameterType.type, parameterType.kotlinType, v, false, true)
if (isVarargInvoke) {
v.astore(OBJECT_TYPE)

View File

@@ -152,7 +152,7 @@ public class CallReceiver extends StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v, boolean allowImplicitCast) {
StackValue currentExtensionReceiver = extensionReceiver;
boolean hasExtensionReceiver = extensionReceiver != none();
if (extensionReceiver instanceof SafeCall) {
@@ -172,7 +172,8 @@ public class CallReceiver extends StackValue {
hasExtensionReceiver ? type : currentExtensionReceiver.type,
hasExtensionReceiver ? kotlinType : currentExtensionReceiver.kotlinType,
v,
dispatchReceiverType.getSize()
dispatchReceiverType.getSize(),
allowImplicitCast
);
}

View File

@@ -293,6 +293,7 @@ public class ClosureCodegen extends MemberCodegen<KtElement> {
public StackValue putInstanceOnStack(@NotNull ExpressionCodegen codegen, @Nullable StackValue functionReferenceReceiver) {
return StackValue.operation(
functionReferenceTarget != null ? K_FUNCTION : asmType,
classDescriptor.getDefaultType(),
v -> {
if (isConst(closure)) {
v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());

View File

@@ -346,7 +346,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
stackValue = new StackValue(stackValue.type, stackValue.kotlinType) {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
stackValueToWrap.put(functionTypeForWrapper, null, v);
invokeCoroutineMigrationMethod(
@@ -371,10 +372,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
public void gen(KtElement expr, Type type, KotlinType kotlinType) {
StackValue value = Type.VOID_TYPE.equals(type) ? genStatement(expr) : gen(expr);
putStackValue(expr, type, kotlinType, value);
putStackValue(expr, type, kotlinType, value, false);
}
private void putStackValue(@Nullable KtElement expr, @NotNull Type type, @Nullable KotlinType kotlinType, @NotNull StackValue value) {
private void putStackValue(
@Nullable KtElement expr,
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull StackValue value,
boolean allowImplicitReturn
) {
// for repl store the result of the last line into special field
if (value.type != Type.VOID_TYPE) {
ScriptContext context = getScriptContext();
@@ -390,7 +397,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
}
value.put(type, kotlinType, v);
value.put(type, kotlinType, v, false, allowImplicitReturn);
}
@Nullable
@@ -1663,7 +1670,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
StackValue valueToReturn = returnedExpression != null ? gen(returnedExpression) : StackValue.none();
putStackValue(returnedExpression, returnType, returnKotlinType, valueToReturn);
putStackValue(returnedExpression, returnType, returnKotlinType, valueToReturn, true);
Label afterReturnLabel = new Label();
generateFinallyBlocksIfNeeded(returnType, returnKotlinType, afterReturnLabel);
@@ -2474,7 +2481,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
coroutineInstanceValue = new StackValue(CoroutineCodegenUtilKt.EXPERIMENTAL_CONTINUATION_ASM_TYPE) {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
releaseContinuation.put(CoroutineCodegenUtilKt.RELEASE_CONTINUATION_ASM_TYPE, v);
invokeCoroutineMigrationMethod(
@@ -2690,7 +2698,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (!isConstructor) { // otherwise already
receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
receiver.put(receiver.type, receiver.kotlinType, v);
receiver.put(receiver.type, receiver.kotlinType, v, false, true);
// In regular cases we add an inline marker just before receiver is loaded (to spill the stack before a suspension)
// But in case of safe call things we get the following bytecode:
@@ -4596,7 +4604,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
arguments.get(1).asElement(),
new StackValue(K_PROPERTY_TYPE) {
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
metadataValue.put(type, kotlinType, v);
}
}

View File

@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.PropertyImportedFromObject
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
import org.jetbrains.kotlin.resolve.isInlineClassType
import org.jetbrains.kotlin.resolve.isUnderlyingPropertyOfInlineClass
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
@@ -352,7 +353,7 @@ class PropertyReferenceCodegen(
codegen.frameMap.getIndex(
codegen.context.functionDescriptor.valueParameters.last()
),
OBJECT_TYPE, targetKotlinType
OBJECT_TYPE, if (targetKotlinType.isInlineClassType()) targetKotlinType else null
),
v
)

View File

@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.kotlin.types.KotlinType;
import org.jetbrains.kotlin.types.SimpleType;
import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
import org.jetbrains.org.objectweb.asm.Label;
import org.jetbrains.org.objectweb.asm.Opcodes;
import org.jetbrains.org.objectweb.asm.Type;
@@ -101,30 +102,50 @@ public abstract class StackValue {
* @param v the visitor used to genClassOrObject the instructions
* @param depth the number of new values put onto the stack
*/
public void moveToTopOfStack(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v, int depth) {
put(type, kotlinType, v);
public void moveToTopOfStack(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v, int depth, boolean allowImplicitCast) {
put(type, kotlinType, v, false, allowImplicitCast);
}
public void put(@NotNull InstructionAdapter v) {
put(type, null, v, false);
public final void put(@NotNull InstructionAdapter v) {
put(type, null, v, false, false);
}
public void put(@NotNull Type type, @NotNull InstructionAdapter v) {
put(type, null, v, false);
public final void put(@NotNull Type type, @NotNull InstructionAdapter v) {
put(type, null, v, false, false);
}
public void put(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
put(type, kotlinType, v, false);
public final void put(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
put(type, kotlinType, v, false, false);
}
public void put(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v, boolean skipReceiver) {
public final void put(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean skipReceiver
) {
put(type, kotlinType, v, skipReceiver, false);
}
public final void put(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean skipReceiver,
boolean allowImplicitCast
) {
if (!skipReceiver) {
putReceiver(v, true);
}
putSelector(type, kotlinType, v);
putSelector(type, kotlinType, v, allowImplicitCast);
}
public abstract void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v);
public abstract void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
);
public boolean isNonStaticAccess(boolean isRead) {
return false;
@@ -525,8 +546,17 @@ public abstract class StackValue {
coerce(this.type, this.kotlinType, toType, toKotlinType, v);
}
protected void coerceFrom(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerce(topOfStackType, topOfStackKotlinType, this.type, this.kotlinType, v);
protected void coerceTo(@NotNull Type toType, @Nullable KotlinType toKotlinType, @NotNull InstructionAdapter v, boolean allowImplicitCast) {
coerce(this.type, this.kotlinType, toType, toKotlinType, v, allowImplicitCast);
}
protected void coerceFrom(
@NotNull Type topOfStackType,
@Nullable KotlinType topOfStackKotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
coerce(topOfStackType, topOfStackKotlinType, this.type, this.kotlinType, v, allowImplicitCast);
}
public static void coerce(
@@ -535,8 +565,27 @@ public abstract class StackValue {
@NotNull Type toType,
@Nullable KotlinType toKotlinType,
@NotNull InstructionAdapter v
) {
coerce(fromType, fromKotlinType, toType, toKotlinType, v, false);
}
public static void coerce(
@NotNull Type fromType,
@Nullable KotlinType fromKotlinType,
@NotNull Type toType,
@Nullable KotlinType toKotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
if (coerceInlineClasses(fromType, fromKotlinType, toType, toKotlinType, v)) return;
if (allowImplicitCast &&
fromKotlinType != null &&
toKotlinType != null &&
fromType.getSort() == Type.OBJECT &&
toType.getSort() == Type.OBJECT &&
!fromType.equals(OBJECT_TYPE) && //TODO: investigate a bunch of failed coroutines tests
!KotlinBuiltIns.isNothingOrNullableNothing(fromKotlinType)) {
if (KotlinTypeChecker.DEFAULT.isSubtypeOf(fromKotlinType, toKotlinType)) return; //use implicit cast
}
coerce(fromType, toType, v);
}
@@ -994,7 +1043,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
coerceTo(type, kotlinType, v);
}
}
@@ -1017,14 +1071,19 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
v.load(index, this.type);
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, false/*need more investigation*/);
v.store(index, this.type);
}
}
@@ -1049,15 +1108,20 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
v.load(index, this.type);
StackValue.genNonNullAssertForLateinit(v, name.asString());
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, false);
v.store(index, this.type);
PseudoInsnsKt.storeNotNull(v);
}
@@ -1098,7 +1162,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
ResolvedCall<FunctionDescriptor> resolvedCall = getResolvedCall(true);
List<? extends ValueArgument> arguments = resolvedCall.getCall().getValueArguments();
assert arguments.size() == 2 : "Resolved call for 'getValue' should have 2 arguments, but was " +
@@ -1142,14 +1211,19 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
coerceTo(type, kotlinType, v);
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
coerceTo(type, kotlinType, v, allowImplicitCast);
}
@Override
public void moveToTopOfStack(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v, int depth) {
public void moveToTopOfStack(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v, int depth, boolean allowImplicitCast) {
if (depth == 0) {
put(type, kotlinType, v);
put(type, kotlinType, v, allowImplicitCast);
}
else if (depth == 1) {
int size = this.type.getSize();
@@ -1164,7 +1238,7 @@ public abstract class StackValue {
throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
}
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
else if (depth == 2) {
int size = this.type.getSize();
@@ -1180,7 +1254,7 @@ public abstract class StackValue {
throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
}
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
else {
throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
@@ -1199,7 +1273,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
if (value instanceof Integer || value instanceof Byte || value instanceof Short) {
v.iconst(((Number) value).intValue());
}
@@ -1220,7 +1299,7 @@ public abstract class StackValue {
}
if (value != null || AsmUtil.isPrimitive(type)) {
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
}
}
@@ -1235,7 +1314,7 @@ public abstract class StackValue {
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, true);
v.astore(this.type);
}
@@ -1246,10 +1325,11 @@ public abstract class StackValue {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
v.aload(this.type); // assumes array and index are on the stack
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
}
@@ -1265,7 +1345,8 @@ public abstract class StackValue {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
coerceTo(type, kotlinType, v);
}
@@ -1306,7 +1387,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
ArgumentGenerator generator = createArgumentGenerator();
@@ -1452,13 +1538,18 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
if (getter == null) {
throw new UnsupportedOperationException("no getter specified");
}
CallGenerator callGenerator = getCallGenerator();
callGenerator.genCall(getter, resolvedGetCall, genDefaultMaskIfPresent(callGenerator), codegen);
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
private boolean genDefaultMaskIfPresent(CallGenerator callGenerator) {
@@ -1622,14 +1713,19 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor());
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, true);
v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor());
}
@@ -1656,7 +1752,7 @@ public abstract class StackValue {
@NotNull StackValue receiver, @NotNull ExpressionCodegen codegen, @Nullable ResolvedCall resolvedCall,
boolean skipLateinitAssertion, @Nullable KotlinType delegateKotlinType
) {
super(type, descriptor.getType(), isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
super(type, descriptor.getOriginal().getType(), isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
this.backingFieldOwner = backingFieldOwner;
this.getter = getter;
this.setter = setter;
@@ -1706,11 +1802,16 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
if (getter == null) {
assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
assert backingFieldOwner != null : "Property should have either a getter or a backingFieldOwner: " + descriptor;
if (inlineConstantIfNeeded(type, kotlinType, v)) return;
if (inlineConstantIfNeeded(type, kotlinType, v, allowImplicitCast)) return;
v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
@@ -1723,7 +1824,7 @@ public abstract class StackValue {
genNonNullAssertForLateinit(v, this.descriptor.getName().asString());
}
}
coerceTo(type, kotlinType, v);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
else {
PropertyGetterDescriptor getterDescriptor = descriptor.getGetter();
@@ -1738,7 +1839,7 @@ public abstract class StackValue {
}
Type typeOfValueOnStack = getter.getReturnType();
KotlinType kotlinTypeOfValueOnStack = getterDescriptor.getReturnType();
KotlinType kotlinTypeOfValueOnStack = getterDescriptor.getOriginal().getReturnType();
if (DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
if (this.type.equals(K_CLASS_TYPE)) {
wrapJavaClassIntoKClass(v);
@@ -1752,7 +1853,7 @@ public abstract class StackValue {
}
}
coerce(typeOfValueOnStack, kotlinTypeOfValueOnStack, type, kotlinType, v);
coerce(typeOfValueOnStack, kotlinTypeOfValueOnStack, type, kotlinType, v, allowImplicitCast);
// For non-private lateinit properties in companion object, the assertion is generated in the public getFoo method
// in the companion and _not_ in the synthetic accessor access$getFoo$cp in the outer class. The reason is that this way,
@@ -1775,19 +1876,29 @@ public abstract class StackValue {
}
}
private boolean inlineConstantIfNeeded(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
private boolean inlineConstantIfNeeded(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
if (JvmCodegenUtil.isInlinedJavaConstProperty(descriptor)) {
return inlineConstant(type, kotlinType, v);
return inlineConstant(type, kotlinType, v, allowImplicitCast);
}
if (descriptor.isConst() && codegen.getState().getShouldInlineConstVals()) {
return inlineConstant(type, kotlinType, v);
return inlineConstant(type, kotlinType, v, allowImplicitCast);
}
return false;
}
private boolean inlineConstant(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
private boolean inlineConstant(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
assert AsmUtil.isPrimitive(this.type) || AsmTypes.JAVA_STRING_TYPE.equals(this.type) :
"Const property should have primitive or string type: " + descriptor;
assert isStaticPut : "Const property should be static" + descriptor;
@@ -1800,7 +1911,7 @@ public abstract class StackValue {
value = ((Double) value).floatValue();
}
StackValue.constant(value, this.type, this.kotlinType).putSelector(type, kotlinType, v);
StackValue.constant(value, this.type, this.kotlinType).putSelector(type, kotlinType, v, allowImplicitCast);
return true;
}
@@ -1830,7 +1941,7 @@ public abstract class StackValue {
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
if (setter == null) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, true);
assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
assert backingFieldOwner != null : "Property should have either a setter or a backingFieldOwner: " + descriptor;
v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
@@ -1893,7 +2004,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
generator.gen(expression, type, kotlinType);
}
}
@@ -1924,20 +2040,25 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
Type refType = refType(this.type);
Type sharedType = sharedTypeForType(this.type);
v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
if (isLateinit) {
StackValue.genNonNullAssertForLateinit(v, name.asString());
}
coerceFrom(refType, null, v);
coerceTo(type, kotlinType, v);
coerceFrom(refType, null, v, true);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, true);
Type refType = refType(this.type);
Type sharedType = sharedTypeForType(this.type);
v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
@@ -1989,20 +2110,25 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
Type sharedType = sharedTypeForType(this.type);
Type refType = refType(this.type);
v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
if (isLateinit) {
StackValue.genNonNullAssertForLateinit(v, variableName.asString());
}
coerceFrom(refType, null, v);
coerceTo(type, kotlinType, v);
coerceFrom(refType, null, v, false);
coerceTo(type, kotlinType, v, allowImplicitCast);
}
@Override
public void storeSelector(@NotNull Type topOfStackType, @Nullable KotlinType topOfStackKotlinType, @NotNull InstructionAdapter v) {
coerceFrom(topOfStackType, topOfStackKotlinType, v);
coerceFrom(topOfStackType, topOfStackKotlinType, v, true);
v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor());
}
@@ -2027,7 +2153,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper);
stackValue.put(
coerceType ? type : stackValue.type,
@@ -2048,7 +2179,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
if (!type.equals(Type.VOID_TYPE)) {
v.load(index, Type.INT_TYPE);
coerceTo(type, kotlinType, v);
@@ -2068,7 +2204,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
v.iinc(index, increment);
if (!type.equals(Type.VOID_TYPE)) {
v.load(index, Type.INT_TYPE);
@@ -2095,13 +2236,18 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
value = StackValue.complexReceiver(value, true, false, true);
value.put(this.type, this.kotlinType, v);
value.store(codegen.invokeFunction(resolvedCall, StackValue.onStack(this.type, this.kotlinType)), v, true);
value.put(this.type, this.kotlinType, v, true);
value.put(this.type, this.kotlinType, v, true, false);
coerceTo(type, kotlinType, v);
}
}
@@ -2219,7 +2365,8 @@ public abstract class StackValue {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
boolean wasPut = false;
StackValue receiver = originalValueWithReceiver.receiver;
@@ -2252,10 +2399,11 @@ public abstract class StackValue {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
for (StackValue instruction : instructions) {
instruction.put(instruction.type, instruction.kotlinType, v);
instruction.put(instruction.type, instruction.kotlinType, v, false, allowImplicitCast);
}
}
}
@@ -2279,9 +2427,10 @@ public abstract class StackValue {
@Override
public void putSelector(
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v
@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
originalValue.putSelector(type, kotlinType, v);
originalValue.putSelector(type, kotlinType, v, allowImplicitCast);
}
@Override
@@ -2338,7 +2487,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
receiver.put(this.type, this.kotlinType, v);
if (ifNull != null) {
//not a primitive
@@ -2359,7 +2513,12 @@ public abstract class StackValue {
}
@Override
public void putSelector(@NotNull Type type, @Nullable KotlinType kotlinType, @NotNull InstructionAdapter v) {
public void putSelector(
@NotNull Type type,
@Nullable KotlinType kotlinType,
@NotNull InstructionAdapter v,
boolean allowImplicitCast
) {
Label end = new Label();
v.goTo(end);

View File

@@ -27,8 +27,13 @@ class CoercionValue(
private val underlyingKotlinType: KotlinType? // type of the underlying parameter for inline class
) : StackValue(castType, castKotlinType, value.canHaveSideEffects()) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
value.putSelector(value.type, value.kotlinType, v)
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
value.putSelector(value.type, value.kotlinType, v, allowImplicitCast)
// consider the following example:
@@ -63,8 +68,13 @@ class StackValueWithLeaveTask(
stackValue.putReceiver(v, isRead)
}
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
stackValue.putSelector(type, kotlinType, v)
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
stackValue.putSelector(type, kotlinType, v, allowImplicitCast)
leaveTasks(stackValue)
}
}
@@ -75,9 +85,14 @@ open class OperationStackValue(
val lambda: (v: InstructionAdapter) -> Unit
) : StackValue(resultType, resultKotlinType) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
lambda(v)
coerceTo(type, kotlinType, v)
coerceTo(type, kotlinType, v, allowImplicitCast)
}
}

View File

@@ -30,7 +30,12 @@ class CallBasedInExpressionGenerator(
private fun gen(argument: StackValue): BranchedValue =
object : BranchedValue(argument, null, argument.type, Opcodes.IFEQ) {
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
invokeFunction(v)
coerceTo(type, kotlinType, v)
}

View File

@@ -3400,6 +3400,41 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("generic.kt")
public void testGeneric() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/generic.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -167,11 +167,11 @@ class ExpressionCodegen(
fun markLineNumber(element: IrElement) = element.markLineNumber(true)
// TODO remove
fun gen(expression: IrExpression, type: Type, irType: IrType, data: BlockInfo): StackValue {
fun gen(expression: IrExpression, type: Type, irType: IrType, data: BlockInfo, allowImplicitCast: Boolean = false): StackValue {
if (expression.attributeOwnerId === context.fakeContinuation) {
addFakeContinuationMarker(mv)
} else {
expression.accept(this, data).materializeAt(type, irType)
expression.accept(this, data).materializeAt(type, irType, allowImplicitCast)
}
return StackValue.onStack(type, irType.toKotlinType())
}
@@ -424,7 +424,8 @@ class ExpressionCodegen(
expression.dispatchReceiver?.let { receiver ->
val type = if ((expression as? IrCall)?.superQualifierSymbol != null) receiver.asmType else callable.owner
callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data)
// Type mapper could use more specific type for invoke instruction and it will cause inconsistency between irType and asmType below (see kt10822.kt)
callGenerator.genValueAndPut(callee.dispatchReceiverParameter!!, receiver, type, this, data, false)
}
expression.extensionReceiver?.let { receiver ->
@@ -484,7 +485,7 @@ class ExpressionCodegen(
MaterialValue(this, AsmTypes.K_CLASS_ARRAY_TYPE, expression.type)
}
else ->
MaterialValue(this, callable.asmMethod.returnType, callee.returnType)
MaterialValue(this, callable.asmMethod.returnType, callable.actualReturnType)
}
}
@@ -567,7 +568,7 @@ class ExpressionCodegen(
if (callee.origin == IrDeclarationOrigin.FIELD_FOR_ENUM_ENTRY) {
value.materialize()
} else {
value.materializeAt(fieldType, callee.type)
value.materializeAt(fieldType, callee.type, true)
}
expression.markLineNumber(startOffset = true)
@@ -730,7 +731,7 @@ class ExpressionCodegen(
return unitValue
}
override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue {
override fun visitReturn(expression: IrReturn, data: BlockInfo): PromisedValue {
val returnTarget = expression.returnTargetSymbol.owner
val owner =
returnTarget as? IrFunction
@@ -750,7 +751,7 @@ class ExpressionCodegen(
val returnType = if (owner == irFunction) signature.returnType else methodSignatureMapper.mapReturnType(owner)
val afterReturnLabel = Label()
expression.value.accept(this, data).materializeAt(returnType, owner.returnType)
expression.value.accept(this, data).materializeAt(returnType, owner.returnType, true)
generateFinallyBlocksIfNeeded(returnType, afterReturnLabel, data)
expression.markLineNumber(startOffset = true)
if (isNonLocalReturn) {
@@ -1007,11 +1008,11 @@ class ExpressionCodegen(
mv.mark(tryCatchBlockEnd)
// TODO: generate a common `finally` for try & catch blocks here? Right now this breaks the inliner.
return object : PromisedValue(this, tryAsmType, aTry.type) {
override fun materializeAt(target: Type, irTarget: IrType) {
override fun materializeAt(target: Type, irTarget: IrType, allowImplicitCasts: Boolean) {
if (savedValue != null) {
mv.load(savedValue, tryAsmType)
frameMap.leaveTemp(tryAsmType)
super.materializeAt(target, irTarget)
super.materializeAt(target, irTarget, allowImplicitCasts)
} else {
unitValue.materializeAt(target, irTarget)
}

View File

@@ -37,9 +37,10 @@ interface IrCallGenerator {
argumentExpression: IrExpression,
parameterType: Type,
codegen: ExpressionCodegen,
blockInfo: BlockInfo
blockInfo: BlockInfo,
allowImplicitCast: Boolean = true
) {
codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo)
codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo, allowImplicitCast)
}
object DefaultCallGenerator : IrCallGenerator

View File

@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.backend.jvm.codegen
import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Type
@@ -15,7 +16,8 @@ class IrCallableMethod(
val owner: Type,
val invokeOpcode: Int,
val signature: JvmMethodSignature,
val isInterfaceMethod: Boolean
val isInterfaceMethod: Boolean,
val actualReturnType: IrType
) {
val asmMethod: Method = signature.asmMethod

View File

@@ -72,14 +72,15 @@ class IrInlineCodegen(
argumentExpression: IrExpression,
parameterType: Type,
codegen: ExpressionCodegen,
blockInfo: BlockInfo
blockInfo: BlockInfo,
allowImplicitCast: Boolean
) {
if (codegen.irFunction.isInvokeSuspendOfContinuation()) {
// In order to support java interop of inline suspend functions, we generate continuations for these inline suspend functions.
// These functions should behave as ordinary suspend functions, i.e. we should not inline the content of the inline function
// into continuation.
// Thus, we should put its arguments to stack.
super.genValueAndPut(irValueParameter, argumentExpression, parameterType, codegen, blockInfo)
super.genValueAndPut(irValueParameter, argumentExpression, parameterType, codegen, blockInfo, allowImplicitCast)
}
val isInlineParameter = irValueParameter.isInlineParameter()

View File

@@ -298,7 +298,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
if (callee !is IrSimpleFunction) {
check(callee is IrConstructor) { "Function must be a simple function or a constructor: ${callee.render()}" }
return IrCallableMethod(owner, Opcodes.INVOKESPECIAL, mapSignatureSkipGeneric(callee), false)
return IrCallableMethod(owner, Opcodes.INVOKESPECIAL, mapSignatureSkipGeneric(callee), false, callee.returnType)
}
val isInterface = calleeParent.isJvmInterface
@@ -316,7 +316,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
val signature = mapOverriddenSpecialBuiltinIfNeeded(caller, declaration, isSuperCall)
?: mapSignatureSkipGeneric(declaration)
return IrCallableMethod(owner, invokeOpcode, signature, isInterface)
return IrCallableMethod(owner, invokeOpcode, signature, isInterface, declaration.returnType)
}
// TODO: get rid of this (probably via some special lowering)

View File

@@ -11,8 +11,10 @@ import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.InlineClassAbi
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
@@ -21,9 +23,10 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
// A value that may not have been fully constructed yet. The ability to "roll back" code generation
// is useful for certain optimizations.
abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val irType: IrType) {
// If this value is immaterial, construct an object on the top of the stack. This
// must always be done before generating other values or emitting raw bytecode.
open fun materializeAt(target: Type, irTarget: IrType) {
open fun materializeAt(target: Type, irTarget: IrType, allowImplicitCasts: Boolean = false) {
val erasedSourceType = irType.eraseTypeParameters()
val erasedTargetType = irTarget.eraseTypeParameters()
val isFromTypeInlineClass = erasedSourceType.classOrNull!!.owner.isInline
@@ -54,6 +57,15 @@ abstract class PromisedValue(val codegen: ExpressionCodegen, val type: Type, val
}
if (type != target) {
if (allowImplicitCasts && type.sort == Type.OBJECT && target.sort == Type.OBJECT &&
type != AsmTypes.VOID_WRAPPER_TYPE &&
type != AsmTypes.OBJECT_TYPE &&
//TODO: Missed type parameters in coroutines types
irType.classifierOrNull?.let { (it.owner as? IrClass)?.origin == JvmLoweredDeclarationOrigin.SUSPEND_LAMBDA } != true &&
irType.isSubtypeOf(irTarget, codegen.context.irBuiltIns)
) {
return
}
StackValue.coerce(type, target, mv)
}
}
@@ -85,7 +97,7 @@ abstract class BooleanValue(codegen: ExpressionCodegen) :
abstract fun jumpIfFalse(target: Label)
abstract fun jumpIfTrue(target: Label)
override fun materializeAt(target: Type, irTarget: IrType) {
override fun materializeAt(target: Type, irTarget: IrType, allowImplicitCasts: Boolean) {
val const0 = Label()
val end = Label()
jumpIfFalse(const0)
@@ -103,7 +115,7 @@ abstract class BooleanValue(codegen: ExpressionCodegen) :
class BooleanConstant(codegen: ExpressionCodegen, val value: Boolean) : BooleanValue(codegen) {
override fun jumpIfFalse(target: Label) = if (value) Unit else mv.goTo(target)
override fun jumpIfTrue(target: Label) = if (value) mv.goTo(target) else Unit
override fun materializeAt(target: Type, irTarget: IrType) {
override fun materializeAt(target: Type, irTarget: IrType, allowImplicitCasts: Boolean) {
mv.iconst(if (value) 1 else 0)
if (Type.BOOLEAN_TYPE != target) {
StackValue.coerce(Type.BOOLEAN_TYPE, target, mv)

View File

@@ -29,7 +29,7 @@ object ArraySet : IntrinsicMethod() {
val elementType = AsmUtil.correctElementType(receiver.type)
val elementIrType = receiver.irType.getArrayElementType(codegen.context.irBuiltIns)
expression.getValueArgument(0)!!.accept(codegen, data).materializeAt(Type.INT_TYPE, codegen.context.irBuiltIns.intType)
expression.getValueArgument(1)!!.accept(codegen, data).materializeAt(elementType, elementIrType)
expression.getValueArgument(1)!!.accept(codegen, data).materializeAt(elementType, elementIrType, true)
codegen.mv.astore(elementType)
return codegen.unitValue
}

View File

@@ -29,9 +29,9 @@ object UnsafeCoerce : IntrinsicMethod() {
val arg = expression.getValueArgument(0)!!
val result = arg.accept(codegen, data)
return object : PromisedValue(codegen, toType, to) {
override fun materializeAt(target: Type, irTarget: IrType) {
override fun materializeAt(target: Type, irTarget: IrType, allowImplicitCasts: Boolean) {
result.materializeAt(fromType, from)
super.materializeAt(target, irTarget)
super.materializeAt(target, irTarget, allowImplicitCasts)
}
override fun discard() {

View File

@@ -0,0 +1,28 @@
fun cond() = true
var result = ""
open class Base
open class Derived : Base() {
fun test(base: Base, base2: Base) {
result += "O"
}
}
open class Child1 : Derived()
open class Child2 : Derived()
fun Derived.test2(base: Base, base2: Base) {
result += "K"
}
fun test(child1: Child1?,child2: Child2) {
(child1 ?: child2).test(child1 ?: child2, child1 ?: child2)
(child1 ?: child2).test2(child1 ?: child2, child1 ?: child2)
}
fun box(): String {
test(Child1(), Child2())
return result
}

View File

@@ -0,0 +1,26 @@
fun cond() = true
var result = ""
open class Base
open class Derived : Base() {
fun test(base: Base, base2: Base) {
result += "O"
}
}
open class Child1 : Derived()
open class Child2 : Derived()
fun Derived.test2(base: Base, base2: Base) {
result += "K"
}
fun box(): String {
(if (cond()) Child1() else Child2()).test(if (cond()) Child1() else Child2(), if (cond()) Child1() else Child2())
(if (cond()) Child1() else Child2()).test2(if (cond()) Child1() else Child2(), if (cond()) Child1() else Child2())
return result
}

View File

@@ -0,0 +1,26 @@
fun cond() = true
var result = ""
open class Base
open class Derived : Base() {
fun test(base: Base, base2: Base) {
result += "O"
}
}
open class Child1 : Derived()
open class Child2 : Derived()
fun Derived.test2(base: Base, base2: Base) {
result += "K"
}
fun box(): String {
(if (cond()) Child1() else return "fail 0").test(if (cond()) Child1() else return "fail 1", if (cond()) Child1() else return "fail 2")
(if (cond()) Child1() else return "fail 00").test2(if (cond()) Child1() else return "fail 3", if (cond()) Child1() else return "fail 4")
return result
}

View File

@@ -0,0 +1,24 @@
var result = ""
open class Base
open class Derived : Base() {
fun test(base: Base, base2: Base) {
result += "O"
}
}
open class Child1 : Derived()
open class Child2 : Derived()
fun Derived.testExt(base: Base, base2: Base) {
result += "K"
}
fun box(): String {
Child2().test(try { Child1() } finally { Child2()} , try { Child1() } finally { Child2() } )
Child2().testExt(try { Child1() } finally { Child2() } , try { Child1() } finally { Child2() } )
return result
}

View File

@@ -0,0 +1,16 @@
open class A {
fun foo(): String {
return "OK"
}
}
open class B : A()
fun<T : A> test(init: () -> T): T = init()
fun call(b: B ) = b
fun box(): String {
return call(test { B() }).foo()
}

View File

@@ -0,0 +1,20 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
open class TransformationInfo
class MyTransformationInfo(val value: String) : TransformationInfo()
abstract class ObjectTransformer<out T : TransformationInfo>(@JvmField val transformationInfo: T)
class MyTransformer(info: MyTransformationInfo): ObjectTransformer<MyTransformationInfo>(info) {
fun test(): String {
return test(transformationInfo)
}
fun test(info: MyTransformationInfo): String {
return info.value
}
}
fun box(): String {
return MyTransformer(MyTransformationInfo("OK")).test()
}

View File

@@ -0,0 +1,27 @@
interface FirDeclaration
interface FirSymbolOwner<E> where E : FirSymbolOwner<E>, E : FirDeclaration
abstract class AbstractFirBasedSymbol<E> : FirSymbolOwner<E> where E : FirSymbolOwner<E>, E : FirDeclaration {
lateinit var fir: E
}
open class FirClassSymbol<E : FirClass<E>>: AbstractFirBasedSymbol<E>()
open class FirClass<F : FirClass<F>> : FirSymbolOwner<F>, FirDeclaration
open class FirRegularClass : FirClass<FirRegularClass>()
open class ClassFirBasedSymbol : AbstractFirBasedSymbol<FirRegularClass>()
fun test(symbol: ClassFirBasedSymbol) {
test(symbol.fir)
}
fun test(p: FirRegularClass) {
}
fun box(): String {
val classFirBasedSymbol = ClassFirBasedSymbol()
classFirBasedSymbol.fir = FirRegularClass()
test(classFirBasedSymbol)
return "OK"
}

View File

@@ -0,0 +1,33 @@
open class SuperBase
open class Base : SuperBase() {
fun test(base: Base) {
testSuper(base)
}
fun testSuper(base: SuperBase) {
}
}
open class Derived : Base()
fun Base.testExt(base: Base) {
testExtSuper(base)
}
fun SuperBase.testExtSuper(base: SuperBase) {
}
fun test() {
Derived().test(Derived())
Derived().testExt(Derived())
}
// JVM_TEMPLATES:
// 0 CHECKCAST
// JVM_IR_TEMPLATES:
// 0 CHECKCAST

View File

@@ -0,0 +1,23 @@
fun cond() = true
open class Base
open class Derived : Base() {
fun test(base: Base, base2: Base) {
}
}
open class Child1 : Derived()
open class Child2 : Derived()
fun Derived.test2(base: Base, base2: Base) {
}
fun test() {
(if (cond()) Child1() else Child2()).test(if (cond()) Child1() else Child2(), if (cond()) Child1() else Child2())
(if (cond()) Child1() else Child2()).test2(if (cond()) Child1() else Child2(), if (cond()) Child1() else Child2())
}
// 12 CHECKCAST
// 12 CHECKCAST Derived

View File

@@ -0,0 +1,35 @@
open class SuperBase
open class Base : SuperBase()
open class Derived : Base()
open class BaseGeneric<T: SuperBase> {
fun test(p: T) : T = p
}
open class DerivedGeneric : BaseGeneric<Derived>()
@JvmField
var property: Base = Base()
fun test(array: Array<Base>) {
val factory = DerivedGeneric();
property = factory.test(Derived())
array[0] = factory.test(Derived())
var captured = Base();
{
captured = factory.test(Derived())
}()
}
// 0 CHECKCAST SuperBase
// JVM_TEMPLATES:
// 4 CHECKCAST
// 1 CHECKCAST kotlin/jvm/functions/Function0
// 3 CHECKCAST Base
// JVM_IR_TEMPLATES:
// 2 CHECKCAST
// 2 CHECKCAST Base

View File

@@ -0,0 +1,17 @@
fun test(s: () -> Unit) {
}
fun test() {
test { } //static
var captured: Any = "123"
test {
captured
} //non-static
}
// JVM_TEMPLATES:
// 0 CHECKCAST
// there is a problem with subtype cheking for lambda class against FunctionX<...>
// JVM_IR_TEMPLATES:
// 2 CHECKCAST

View File

@@ -0,0 +1,8 @@
open class Base
open class Derived : Base()
fun test() : Base {
return Derived()
}
// 0 CHECKCAST

View File

@@ -0,0 +1,22 @@
open class Base
open class Derived : Base()
@JvmField
var property: Base = Base()
fun test(array: Array<Base>) {
property = Derived()
array[0] = Derived()
var captured = Base();
{
captured = Derived()
}()
}
// JVM_TEMPLATES:
// 1 CHECKCAST
// 1 CHECKCAST kotlin/jvm/functions/Function0
// JVM_IR_TEMPLATES:
// 0 CHECKCAST

View File

@@ -0,0 +1,28 @@
open class Base
open class Derived : Base()
@JvmField
var property: Base = Base()
fun test(array: Array<Base>) {
property = Derived() as Derived
property = Derived() as Base
array[0] = Derived() as Derived
array[0] = Derived() as Base
var captured = Base() as Base;
{
captured = Derived() as Derived
captured = Derived() as Base
}()
}
// JVM_TEMPLATES:
// 4 CHECKCAST
// 1 CHECKCAST kotlin/jvm/functions/Function0
// This checkcast should not be generated
// 3 CHECKCAST Base
// JVM_IR_TEMPLATES:
// 0 CHECKCAST

View File

@@ -0,0 +1,29 @@
interface A
open class Base
open class Derived : Base()
open class Derived2 : Base()
fun cond(): Boolean = true
@JvmField
var property: Base = Base()
fun test(array: Array<Base>) {
property = if (cond()) Derived() else Derived2()
array[0] = if (cond()) Derived() else Derived2()
var captured = Base();
{
captured = if (cond()) Derived() else Derived2()
}()
}
// JVM_TEMPLATES:
// 7 CHECKCAST
// 1 CHECKCAST kotlin/jvm/functions/Function0
// 6 CHECKCAST Base
// JVM_IR_TEMPLATES:
// 6 CHECKCAST
// 6 CHECKCAST Base

View File

@@ -3420,6 +3420,41 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("generic.kt")
public void testGeneric() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/generic.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -884,6 +884,59 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
public void testKt22714() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/kt22714.kt");
}
@TestMetadata("compiler/testData/codegen/bytecodeText/checkcast/implicit")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Implicit extends AbstractBytecodeTextTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
}
public void testAllFilesPresentInImplicit() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/checkcast/implicit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("functionCall.kt")
public void testFunctionCall() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/functionCall.kt");
}
@TestMetadata("functionCallWithExplicitCastOnMerge.kt")
public void testFunctionCallWithExplicitCastOnMerge() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/functionCallWithExplicitCastOnMerge.kt");
}
@TestMetadata("generic.kt")
public void testGeneric() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/generic.kt");
}
@TestMetadata("lambdaAsParameter.kt")
public void testLambdaAsParameter() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/lambdaAsParameter.kt");
}
@TestMetadata("return.kt")
public void testReturn() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/return.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/simple.kt");
}
@TestMetadata("simpleExplicitCast.kt")
public void testSimpleExplicitCast() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/simpleExplicitCast.kt");
}
@TestMetadata("simpleWithExplicitCastOnMerge.kt")
public void testSimpleWithExplicitCastOnMerge() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/simpleWithExplicitCastOnMerge.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/coercionToUnitOptimization")

View File

@@ -3420,6 +3420,41 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("generic.kt")
public void testGeneric() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/generic.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -3400,6 +3400,41 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("generic.kt")
public void testGeneric() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/generic.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -884,6 +884,59 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
public void testKt22714() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/kt22714.kt");
}
@TestMetadata("compiler/testData/codegen/bytecodeText/checkcast/implicit")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Implicit extends AbstractIrBytecodeTextTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath);
}
public void testAllFilesPresentInImplicit() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/bytecodeText/checkcast/implicit"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@TestMetadata("functionCall.kt")
public void testFunctionCall() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/functionCall.kt");
}
@TestMetadata("functionCallWithExplicitCastOnMerge.kt")
public void testFunctionCallWithExplicitCastOnMerge() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/functionCallWithExplicitCastOnMerge.kt");
}
@TestMetadata("generic.kt")
public void testGeneric() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/generic.kt");
}
@TestMetadata("lambdaAsParameter.kt")
public void testLambdaAsParameter() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/lambdaAsParameter.kt");
}
@TestMetadata("return.kt")
public void testReturn() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/return.kt");
}
@TestMetadata("simple.kt")
public void testSimple() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/simple.kt");
}
@TestMetadata("simpleExplicitCast.kt")
public void testSimpleExplicitCast() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/simpleExplicitCast.kt");
}
@TestMetadata("simpleWithExplicitCastOnMerge.kt")
public void testSimpleWithExplicitCastOnMerge() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/checkcast/implicit/simpleWithExplicitCastOnMerge.kt");
}
}
}
@TestMetadata("compiler/testData/codegen/bytecodeText/coercionToUnitOptimization")

View File

@@ -2720,6 +2720,36 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR_ES6, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -2730,6 +2730,36 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -2730,6 +2730,36 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/checkcastOptimization"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
}
@TestMetadata("functionCallWithElvis.kt")
public void testFunctionCallWithElvis() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithElvis.kt");
}
@TestMetadata("functionCallWithIf.kt")
public void testFunctionCallWithIf() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithIf.kt");
}
@TestMetadata("functionCallWithReturn.kt")
public void testFunctionCallWithReturn() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithReturn.kt");
}
@TestMetadata("functionCallWithTry.kt")
public void testFunctionCallWithTry() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/functionCallWithTry.kt");
}
@TestMetadata("genereicParamDowncast.kt")
public void testGenereicParamDowncast() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genereicParamDowncast.kt");
}
@TestMetadata("genericProperty.kt")
public void testGenericProperty() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/genericProperty.kt");
}
@TestMetadata("kt19128.kt")
public void testKt19128() throws Exception {
runTest("compiler/testData/codegen/box/checkcastOptimization/kt19128.kt");

View File

@@ -36,7 +36,12 @@ class ResourcePropertyStackValue(
assert(containerOptions.containerType != AndroidContainerType.UNKNOWN)
}
override fun putSelector(type: Type, kotlinType: KotlinType?, v: InstructionAdapter) {
override fun putSelector(
type: Type,
kotlinType: KotlinType?,
v: InstructionAdapter,
allowImplicitCast: Boolean
) {
val returnTypeString = typeMapper.mapType(resource.type.lowerIfFlexible()).className
if (AndroidConst.FRAGMENT_FQNAME == returnTypeString || AndroidConst.SUPPORT_FRAGMENT_FQNAME == returnTypeString || AndroidConst.ANDROIDX_SUPPORT_FRAGMENT_FQNAME == returnTypeString) {
return putSelectorForFragment(v)