Fix for KT-7999: Wrong result when use nullable types as reified parameter, KT-8043: Unsafe cast to reified parameter throws NPE instead of TypeCastException
#KT-7999 Fixed #KT-8043 Fixed ~
This commit is contained in:
@@ -57,7 +57,6 @@ import org.jetbrains.kotlin.lexer.KtTokens;
|
|||||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||||
import org.jetbrains.kotlin.name.Name;
|
import org.jetbrains.kotlin.name.Name;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
import org.jetbrains.kotlin.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
|
||||||
@@ -2483,9 +2482,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mappings.addParameterMappingToNewParameter(
|
mappings.addParameterMappingToNewParameter(
|
||||||
key.getName().getIdentifier(),
|
key.getName().getIdentifier(), type,
|
||||||
parameterDescriptor.getName().getIdentifier()
|
parameterDescriptor.getName().getIdentifier());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return getOrCreateCallGenerator(
|
return getOrCreateCallGenerator(
|
||||||
@@ -3689,13 +3687,8 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (opToken != KtTokens.AS_SAFE) {
|
if (opToken != KtTokens.AS_SAFE) {
|
||||||
if (!TypeUtils.isNullableType(rightType)) {
|
if (!TypeUtils.isNullableType(rightType) && !TypeUtils.isReifiedTypeParameter(rightType)) {
|
||||||
v.dup();
|
CodegenUtilKt.generateNullCheckForNonSafeAs(v, rightType);
|
||||||
Label nonnull = new Label();
|
|
||||||
v.ifnonnull(nonnull);
|
|
||||||
genThrow(v, "kotlin/TypeCastException", "null cannot be cast to non-null type " +
|
|
||||||
DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(rightType));
|
|
||||||
v.mark(nonnull);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -3759,7 +3752,7 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
if (leaveExpressionOnStack) {
|
if (leaveExpressionOnStack) {
|
||||||
v.dup();
|
v.dup();
|
||||||
}
|
}
|
||||||
CodegenUtilKt.generateIsCheck(v, kotlinType, new Function1<InstructionAdapter, Unit>() {
|
CodegenUtilKt.generateIsCheck(v, kotlinType.isMarkedNullable() && !TypeUtils.isReifiedTypeParameter(kotlinType), new Function1<InstructionAdapter, Unit>() {
|
||||||
@Override
|
@Override
|
||||||
public Unit invoke(InstructionAdapter adapter) {
|
public Unit invoke(InstructionAdapter adapter) {
|
||||||
generateInstanceOfInstruction(kotlinType);
|
generateInstanceOfInstruction(kotlinType);
|
||||||
@@ -3794,8 +3787,8 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
parentCodegen.getReifiedTypeParametersUsages().
|
parentCodegen.getReifiedTypeParametersUsages().
|
||||||
addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
|
addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
|
||||||
}
|
}
|
||||||
|
boolean putNullableFlag = ReifiedTypeInliner.isNullableMarkerInstruction(markerMethodName) && type.isMarkedNullable();
|
||||||
v.visitLdcInsn(typeParameterDescriptor.getName().asString());
|
v.visitLdcInsn(typeParameterDescriptor.getName().asString() + (putNullableFlag ? "?" : ""));
|
||||||
v.invokestatic(
|
v.invokestatic(
|
||||||
IntrinsicMethods.INTRINSICS_CLASS_NAME, markerMethodName,
|
IntrinsicMethods.INTRINSICS_CLASS_NAME, markerMethodName,
|
||||||
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false
|
Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)), false
|
||||||
|
|||||||
@@ -911,7 +911,7 @@ public class FunctionCodegen {
|
|||||||
iv.ifnonnull(afterBarrier);
|
iv.ifnonnull(afterBarrier);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
CodegenUtilKt.generateIsCheck(iv, kotlinType, new Function1<InstructionAdapter, Unit>() {
|
CodegenUtilKt.generateIsCheck(iv, kotlinType.isMarkedNullable(), new Function1<InstructionAdapter, Unit>() {
|
||||||
@Override
|
@Override
|
||||||
public Unit invoke(InstructionAdapter adapter) {
|
public Unit invoke(InstructionAdapter adapter) {
|
||||||
TypeIntrinsics.instanceOf(adapter, kotlinType, boxType(delegateParameterType));
|
TypeIntrinsics.instanceOf(adapter, kotlinType, boxType(delegateParameterType));
|
||||||
|
|||||||
@@ -18,16 +18,17 @@
|
|||||||
package org.jetbrains.kotlin.codegen
|
package org.jetbrains.kotlin.codegen
|
||||||
|
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
||||||
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
fun generateIsCheck(
|
fun generateIsCheck(
|
||||||
v: InstructionAdapter,
|
v: InstructionAdapter,
|
||||||
type: KotlinType,
|
isNullable: Boolean,
|
||||||
generateInstanceOfInstruction: (InstructionAdapter) -> Unit
|
generateInstanceOfInstruction: (InstructionAdapter) -> Unit
|
||||||
) {
|
) {
|
||||||
if (type.isMarkedNullable) {
|
if (isNullable) {
|
||||||
val nope = Label()
|
val nope = Label()
|
||||||
val end = Label()
|
val end = Label()
|
||||||
|
|
||||||
@@ -51,6 +52,19 @@ fun generateIsCheck(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun generateNullCheckForNonSafeAs(
|
||||||
|
v: InstructionAdapter,
|
||||||
|
type: KotlinType
|
||||||
|
) {
|
||||||
|
with(v) {
|
||||||
|
dup()
|
||||||
|
val nonnull = Label()
|
||||||
|
ifnonnull(nonnull)
|
||||||
|
AsmUtil.genThrow(v, "kotlin/TypeCastException", "null cannot be cast to non-null type " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type))
|
||||||
|
mark(nonnull)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public fun SpecialSignatureInfo.replaceValueParametersIn(sourceSignature: String?): String?
|
public fun SpecialSignatureInfo.replaceValueParametersIn(sourceSignature: String?): String?
|
||||||
= valueParametersSignature?.let { sourceSignature?.replace("^\\(.*\\)".toRegex(), "($it)") }
|
= valueParametersSignature?.let { sourceSignature?.replace("^\\(.*\\)".toRegex(), "($it)") }
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.inline;
|
package org.jetbrains.kotlin.codegen.inline;
|
||||||
|
|
||||||
import com.intellij.openapi.util.Pair;
|
|
||||||
import com.intellij.util.ArrayUtil;
|
import com.intellij.util.ArrayUtil;
|
||||||
import kotlin.jvm.functions.Function0;
|
import kotlin.jvm.functions.Function0;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -237,7 +236,7 @@ public class AnonymousObjectTransformer {
|
|||||||
@NotNull ParametersBuilder capturedBuilder,
|
@NotNull ParametersBuilder capturedBuilder,
|
||||||
boolean isConstructor
|
boolean isConstructor
|
||||||
) {
|
) {
|
||||||
ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions);
|
ReifiedTypeParametersUsages typeParametersToReify = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode);
|
||||||
Parameters parameters = isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode);
|
Parameters parameters = isConstructor ? capturedBuilder.buildParameters() : getMethodParametersWithCaptured(capturedBuilder, sourceNode);
|
||||||
|
|
||||||
RegeneratedLambdaFieldRemapper remapper =
|
RegeneratedLambdaFieldRemapper remapper =
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ public class InlineCodegen extends CallGenerator {
|
|||||||
|
|
||||||
private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
|
private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
|
||||||
MethodNode node = nodeAndSmap.getNode();
|
MethodNode node = nodeAndSmap.getNode();
|
||||||
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions);
|
ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
|
||||||
generateClosuresBodies();
|
generateClosuresBodies();
|
||||||
|
|
||||||
//through generation captured parameters will be added to invocationParamBuilder
|
//through generation captured parameters will be added to invocationParamBuilder
|
||||||
|
|||||||
@@ -311,8 +311,7 @@ public class InlineCodegenUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode beforeNode) {
|
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull InsnList instructions, @NotNull AbstractInsnNode beforeNode) {
|
||||||
InsnList instructions = to.instructions;
|
|
||||||
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
|
ListIterator<AbstractInsnNode> iterator = from.instructions.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
AbstractInsnNode next = iterator.next();
|
AbstractInsnNode next = iterator.next();
|
||||||
@@ -320,6 +319,10 @@ public class InlineCodegenUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void insertNodeBefore(@NotNull MethodNode from, @NotNull MethodNode to, @NotNull AbstractInsnNode beforeNode) {
|
||||||
|
insertNodeBefore(from, to.instructions, beforeNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static MethodNode createEmptyMethodNode() {
|
public static MethodNode createEmptyMethodNode() {
|
||||||
return new MethodNode(API, 0, "fake", "()V", null, null);
|
return new MethodNode(API, 0, "fake", "()V", null, null);
|
||||||
|
|||||||
@@ -18,16 +18,22 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import com.google.common.collect.ImmutableSet
|
import com.google.common.collect.ImmutableSet
|
||||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||||
|
import org.jetbrains.kotlin.codegen.generateIsCheck
|
||||||
|
import org.jetbrains.kotlin.codegen.generateNullCheckForNonSafeAs
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||||
import org.jetbrains.org.objectweb.asm.Type
|
import org.jetbrains.org.objectweb.asm.Type
|
||||||
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
import org.jetbrains.org.objectweb.asm.signature.SignatureReader
|
||||||
import org.jetbrains.org.objectweb.asm.signature.SignatureWriter
|
import org.jetbrains.org.objectweb.asm.signature.SignatureWriter
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
|
|
||||||
|
private class ParameterNameAndNullability(val name: String, val nullable: Boolean)
|
||||||
|
|
||||||
public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) {
|
public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -64,15 +70,23 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
|||||||
Type.getMethodDescriptor(Type.VOID_TYPE), false
|
Type.getMethodDescriptor(Type.VOID_TYPE), false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
public fun isNullableMarkerInstruction(marker: String) = INSTANCEOF_MARKER_METHOD_NAME == marker ||
|
||||||
|
CHECKCAST_MARKER_METHOD_NAME == marker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var maxStackSize = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return set of type parameters' identifiers contained in markers that should be reified further
|
* @return set of type parameters' identifiers contained in markers that should be reified further
|
||||||
* e.g. when we're generating inline function containing reified T
|
* e.g. when we're generating inline function containing reified T
|
||||||
* and another function containing reifiable parts is inlined into that function
|
* and another function containing reifiable parts is inlined into that function
|
||||||
*/
|
*/
|
||||||
public fun reifyInstructions(instructions: InsnList): ReifiedTypeParametersUsages {
|
public fun reifyInstructions(node: MethodNode): ReifiedTypeParametersUsages {
|
||||||
if (parametersMapping == null) return ReifiedTypeParametersUsages()
|
if (parametersMapping == null) return ReifiedTypeParametersUsages()
|
||||||
|
val instructions = node.instructions
|
||||||
|
maxStackSize = 0
|
||||||
var result = ReifiedTypeParametersUsages()
|
var result = ReifiedTypeParametersUsages()
|
||||||
for (insn in instructions.toArray()) {
|
for (insn in instructions.toArray()) {
|
||||||
if (isParametrisedReifiedMarker(insn)) {
|
if (isParametrisedReifiedMarker(insn)) {
|
||||||
@@ -83,6 +97,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.maxStack = node.maxStack + maxStackSize
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,20 +142,25 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
|||||||
* or null if it shouldn't
|
* or null if it shouldn't
|
||||||
*/
|
*/
|
||||||
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): String? {
|
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList): String? {
|
||||||
val mapping = getTypeParameterMapping(insn) ?: return null
|
val parameter = getParameter(insn) ?: return null
|
||||||
|
val mapping = parametersMapping?.get(parameter.name) ?: return null
|
||||||
|
val kotlinType =
|
||||||
|
if (isNullableMarkerInstruction(insn.name) && parameter.nullable)
|
||||||
|
TypeUtils.makeNullable(mapping.type)
|
||||||
|
else
|
||||||
|
mapping.type
|
||||||
|
|
||||||
|
|
||||||
val asmType = mapping.asmType
|
val asmType = mapping.asmType
|
||||||
if (asmType != null) {
|
if (asmType != null) {
|
||||||
val jetType = mapping.type ?: return null
|
|
||||||
|
|
||||||
// process* methods return false if marker should be reified further
|
// process* methods return false if marker should be reified further
|
||||||
// or it's invalid (may be emitted explicitly in code)
|
// or it's invalid (may be emitted explicitly in code)
|
||||||
// they return true if instruction is reified and marker can be deleted
|
// they return true if instruction is reified and marker can be deleted
|
||||||
if (when (insn.name) {
|
if (when (insn.name) {
|
||||||
NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, asmType)
|
NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, asmType)
|
||||||
CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, jetType, asmType, safe = false)
|
CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, kotlinType, asmType, safe = false)
|
||||||
SAFE_CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, jetType, asmType, safe = true)
|
SAFE_CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, instructions, kotlinType, asmType, safe = true)
|
||||||
INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, instructions, jetType, asmType)
|
INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, instructions, kotlinType, asmType)
|
||||||
JAVA_CLASS_MARKER_METHOD_NAME -> processJavaClass(insn, asmType)
|
JAVA_CLASS_MARKER_METHOD_NAME -> processJavaClass(insn, asmType)
|
||||||
else -> false
|
else -> false
|
||||||
}) {
|
}) {
|
||||||
@@ -150,7 +170,8 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
|||||||
|
|
||||||
return null
|
return null
|
||||||
} else {
|
} else {
|
||||||
instructions.set(insn.getPrevious()!!, LdcInsnNode(mapping.newName))
|
val nullableSuffix = if (isNullableMarkerInstruction(insn.name) && kotlinType.isMarkedNullable) "?" else ""
|
||||||
|
instructions.set(insn.previous!!, LdcInsnNode(mapping.newName + nullableSuffix))
|
||||||
return mapping.newName
|
return mapping.newName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,20 +179,66 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
|||||||
private fun processNewArray(insn: MethodInsnNode, parameter: Type) =
|
private fun processNewArray(insn: MethodInsnNode, parameter: Type) =
|
||||||
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
|
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
|
||||||
|
|
||||||
private fun processCheckcast(insn: MethodInsnNode, instructions: InsnList, jetType: KotlinType, asmType: Type, safe: Boolean) =
|
private fun processCheckcast(insn: MethodInsnNode,
|
||||||
|
instructions: InsnList,
|
||||||
|
jetType: KotlinType,
|
||||||
|
asmType: Type,
|
||||||
|
safe: Boolean) =
|
||||||
rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { instanceofInsn: AbstractInsnNode ->
|
rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { instanceofInsn: AbstractInsnNode ->
|
||||||
if (instanceofInsn !is TypeInsnNode) return false
|
if (instanceofInsn !is TypeInsnNode) return false
|
||||||
|
|
||||||
|
addNullCheckForAsIfNeeded(insn.previous!!, instructions, jetType, safe)
|
||||||
TypeIntrinsics.checkcast(instanceofInsn, instructions, jetType, asmType, safe)
|
TypeIntrinsics.checkcast(instanceofInsn, instructions, jetType, asmType, safe)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addNullCheckForAsIfNeeded(insn: AbstractInsnNode, instructions: InsnList, jetType: KotlinType, safe: Boolean) {
|
||||||
|
if (!safe && !TypeUtils.isNullableType(jetType)) {
|
||||||
|
val methodNode = MethodNode(InlineCodegenUtil.API)
|
||||||
|
generateNullCheckForNonSafeAs(InstructionAdapter(methodNode), jetType)
|
||||||
|
|
||||||
|
InlineCodegenUtil.insertNodeBefore(methodNode, instructions, insn)
|
||||||
|
maxStackSize = Math.max(maxStackSize, 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun processInstanceof(insn: MethodInsnNode, instructions: InsnList, jetType: KotlinType, asmType: Type) =
|
private fun processInstanceof(insn: MethodInsnNode, instructions: InsnList, jetType: KotlinType, asmType: Type) =
|
||||||
rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { instanceofInsn: AbstractInsnNode ->
|
rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { instanceofInsn: AbstractInsnNode ->
|
||||||
if (instanceofInsn !is TypeInsnNode) return false
|
if (instanceofInsn !is TypeInsnNode) return false
|
||||||
|
|
||||||
|
addNullCheckForIsIfNeeded(insn, instructions, jetType)
|
||||||
TypeIntrinsics.instanceOf(instanceofInsn, instructions, jetType, asmType)
|
TypeIntrinsics.instanceOf(instanceofInsn, instructions, jetType, asmType)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun addNullCheckForIsIfNeeded(insn: AbstractInsnNode, instructions: InsnList, type: KotlinType) {
|
||||||
|
if (TypeUtils.isNullableType(type)) {
|
||||||
|
val instanceOf = insn.next
|
||||||
|
insertNullCheckAround(instructions, insn.previous!!, instanceOf)
|
||||||
|
maxStackSize = Math.max(maxStackSize, 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun insertNullCheckAround(instructions: InsnList, start: AbstractInsnNode, end: AbstractInsnNode) {
|
||||||
|
val methodNode = MethodNode(InlineCodegenUtil.API)
|
||||||
|
var splitIndex: Int = -1
|
||||||
|
generateIsCheck(InstructionAdapter(methodNode), true) {
|
||||||
|
splitIndex = methodNode.instructions.size()
|
||||||
|
}
|
||||||
|
assert(splitIndex >= 0) {
|
||||||
|
"Split index should be non-negative, but $splitIndex"
|
||||||
|
}
|
||||||
|
|
||||||
|
val nullCheckInsns = methodNode.instructions.toArray()
|
||||||
|
nullCheckInsns.take(splitIndex).forEach {
|
||||||
|
instructions.insertBefore(start, it)
|
||||||
|
}
|
||||||
|
|
||||||
|
nullCheckInsns.drop(splitIndex).reversed().forEach {
|
||||||
|
instructions.insert(end, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline private fun rewriteNextTypeInsn(
|
inline private fun rewriteNextTypeInsn(
|
||||||
marker: MethodInsnNode,
|
marker: MethodInsnNode,
|
||||||
expectedNextOpcode: Int,
|
expectedNextOpcode: Int,
|
||||||
@@ -195,17 +262,16 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getParameterName(insn: MethodInsnNode): String? {
|
private fun getParameter(insn: MethodInsnNode): ParameterNameAndNullability? {
|
||||||
val prev = insn.getPrevious()!!
|
val prev = insn.getPrevious()!!
|
||||||
|
|
||||||
return when (prev.getOpcode()) {
|
val parameterNameWithFlag = when (prev.getOpcode()) {
|
||||||
Opcodes.LDC -> (prev as LdcInsnNode).cst as String
|
Opcodes.LDC -> (prev as LdcInsnNode).cst as String
|
||||||
else -> null
|
else -> return null
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun getTypeParameterMapping(insn: MethodInsnNode): ReifiedTypeParameterMapping? {
|
val parameterName = if (parameterNameWithFlag.endsWith("?")) parameterNameWithFlag.dropLast(1) else parameterNameWithFlag
|
||||||
return parametersMapping?.get(getParameterName(insn) ?: return null)
|
return ParameterNameAndNullability(parameterName, parameterName !== parameterNameWithFlag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +282,8 @@ public class ReifiedTypeParameterMappings() {
|
|||||||
mappingsByName[name] = ReifiedTypeParameterMapping(name, type, asmType, newName = null, signature = signature)
|
mappingsByName[name] = ReifiedTypeParameterMapping(name, type, asmType, newName = null, signature = signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun addParameterMappingToNewParameter(name: String, newName: String) {
|
public fun addParameterMappingToNewParameter(name: String, type: KotlinType, newName: String) {
|
||||||
mappingsByName[name] = ReifiedTypeParameterMapping(name, type = null, asmType = null, newName = newName, signature = null)
|
mappingsByName[name] = ReifiedTypeParameterMapping(name, type = type, asmType = null, newName = newName, signature = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun get(name: String): ReifiedTypeParameterMapping? {
|
operator fun get(name: String): ReifiedTypeParameterMapping? {
|
||||||
@@ -226,7 +292,7 @@ public class ReifiedTypeParameterMappings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class ReifiedTypeParameterMapping(
|
public class ReifiedTypeParameterMapping(
|
||||||
val name: String, val type: KotlinType?, val asmType: Type?, val newName: String?, val signature: String?
|
val name: String, val type: KotlinType, val asmType: Type?, val newName: String?, val signature: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
public class ReifiedTypeParametersUsages {
|
public class ReifiedTypeParametersUsages {
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (null.foo3<Any>() != null) return "fail 1"
|
||||||
|
if (null.foo3<Any?>() != null) return "fail 2"
|
||||||
|
|
||||||
|
if (null.foo3<A>() != null) return "fail 3"
|
||||||
|
if (null.foo3<A?>() != null) return "fail 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo3<Any>() != a) return "fail 5"
|
||||||
|
if (a.foo3<Any?>() != a) return "fail 6"
|
||||||
|
|
||||||
|
if (a.foo3<A>() != a) return "fail 7"
|
||||||
|
if (a.foo3<A?>() != a) return "fail 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
failClassCast { b.foo3<A>(); return "failTypeCast 9" }
|
||||||
|
failClassCast { b.foo3<A?>(); return "failTypeCast 10" }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failClassCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch (e: ClassCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo(): T = this as T
|
||||||
|
|
||||||
|
inline fun <reified Y> Any?.foo2(): Y? = foo<Y?>()
|
||||||
|
|
||||||
|
inline fun <reified Z> Any?.foo3(): Z? = foo2<Z>()
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun case1(): Int =
|
||||||
|
null.castTo<Int?, Int>()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
failTypeCast { case1(); return "failTypeCast 9" }
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failTypeCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
inline fun <reified T, reified R>T.castTo(): R = this as R
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val a = A()
|
||||||
|
if (a.foo<Any>() != a) return "failTypeCast 5"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
fun call(a: String, b: String, c: String, d: String, e: String, f: Any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T: Any> Any?.foo(): T {
|
||||||
|
call("1", "2", "3", "4", "5", this as T)
|
||||||
|
return this as T
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (null.foo<Any>() != null) return "failTypeCast 1"
|
||||||
|
if (null.foo<Any?>() != null) return "failTypeCast 2"
|
||||||
|
|
||||||
|
if (null.foo<A>() != null) return "failTypeCast 3"
|
||||||
|
if (null.foo<A?>() != null) return "failTypeCast 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo<Any>() != a) return "failTypeCast 5"
|
||||||
|
if (a.foo<Any?>() != a) return "failTypeCast 6"
|
||||||
|
|
||||||
|
if (a.foo<A>() != a) return "failTypeCast 7"
|
||||||
|
if (a.foo<A?>() != a) return "failTypeCast 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
failClassCast { b.foo<A>(); return "failTypeCast 9" }
|
||||||
|
failClassCast { b.foo<A?>(); return "failTypeCast 10" }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failTypeCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failClassCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch (e: ClassCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo(): T? = this as T?
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
failTypeCast { null.foo<Any>(); return "failTypeCast 1" }
|
||||||
|
if (null.foo<Any?>() != null) return "failTypeCast 2"
|
||||||
|
|
||||||
|
failTypeCast { null.foo<A>(); return "failTypeCast 3" }
|
||||||
|
if (null.foo<A?>() != null) return "failTypeCast 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo<Any>() != a) return "failTypeCast 5"
|
||||||
|
if (a.foo<Any?>() != a) return "failTypeCast 6"
|
||||||
|
|
||||||
|
if (a.foo<A>() != a) return "failTypeCast 7"
|
||||||
|
if (a.foo<A?>() != a) return "failTypeCast 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
failClassCast { b.foo<A>(); return "failTypeCast 9" }
|
||||||
|
failClassCast { b.foo<A?>(); return "failTypeCast 10" }
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failTypeCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failClassCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch (e: ClassCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo(): T = this as T
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (null.foo<Any>() != null) return "failTypeCast 1"
|
||||||
|
if (null.foo<Any?>() != null) return "failTypeCast 2"
|
||||||
|
|
||||||
|
if (null.foo<A>() != null) return "failTypeCast 3"
|
||||||
|
if (null.foo<A?>() != null) return "failTypeCast 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo<Any>() != a) return "failTypeCast 5"
|
||||||
|
if (a.foo<Any?>() != a) return "failTypeCast 6"
|
||||||
|
|
||||||
|
if (a.foo<A>() != a) return "failTypeCast 7"
|
||||||
|
if (a.foo<A?>() != a) return "failTypeCast 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
if (b.foo<A>() != null) return "fail 9"
|
||||||
|
if (b.foo<A?>() != null) return "fail 10"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failTypeCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun failClassCast(s: () -> Unit) {
|
||||||
|
try {
|
||||||
|
s()
|
||||||
|
}
|
||||||
|
catch (e: TypeCastException) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
catch (e: ClassCastException) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo(): T? = this as? T
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (null.foo3<Any>() != true) return "fail 1"
|
||||||
|
if (null.foo3<Any?>() != true) return "fail 2"
|
||||||
|
|
||||||
|
if (null.foo3<A>() != true) return "fail 3"
|
||||||
|
if (null.foo3<A?>() != true) return "fail 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo3<Any>() != true) return "fail 5"
|
||||||
|
if (a.foo3<Any?>() != true) return "fail 6"
|
||||||
|
|
||||||
|
if (a.foo3<A>() != true) return "fail 7"
|
||||||
|
if (a.foo3<A?>() != true) return "fail 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
if (b.foo3<A>() != false) return "fail 9"
|
||||||
|
if (b.foo3<A?>() != false) return "fail 10"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo() = this is T
|
||||||
|
|
||||||
|
inline fun <reified Y> Any?.foo2() = foo<Y?>()
|
||||||
|
|
||||||
|
inline fun <reified Z> Any?.foo3() = foo2<Z>()
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (null.foo<Any>() != true) return "fail 1"
|
||||||
|
if (null.foo<Any?>() != true) return "fail 2"
|
||||||
|
|
||||||
|
if (null.foo<A>() != true) return "fail 3"
|
||||||
|
if (null.foo<A?>() != true) return "fail 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo<Any>() != true) return "fail 5"
|
||||||
|
if (a.foo<Any?>() != true) return "fail 6"
|
||||||
|
|
||||||
|
if (a.foo<A>() != true) return "fail 7"
|
||||||
|
if (a.foo<A?>() != true) return "fail 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
if (b.foo<A>() != false) return "fail 9"
|
||||||
|
if (b.foo<A?>() != false) return "fail 10"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo() = this is T?
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
if (null.foo<Any>() != false) return "fail 1"
|
||||||
|
if (null.foo<Any?>() != true) return "fail 2"
|
||||||
|
|
||||||
|
if (null.foo<A>() != false) return "fail 3"
|
||||||
|
if (null.foo<A?>() != true) return "fail 4"
|
||||||
|
|
||||||
|
val a = A()
|
||||||
|
|
||||||
|
if (a.foo<Any>() != true) return "fail 5"
|
||||||
|
if (a.foo<Any?>() != true) return "fail 6"
|
||||||
|
|
||||||
|
if (a.foo<A>() != true) return "fail 7"
|
||||||
|
if (a.foo<A?>() != true) return "fail 8"
|
||||||
|
|
||||||
|
val b = B()
|
||||||
|
|
||||||
|
if (b.foo<A>() != false) return "fail 9"
|
||||||
|
if (b.foo<A?>() != false) return "fail 10"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
class A
|
||||||
|
class B
|
||||||
|
|
||||||
|
inline fun <reified T> Any?.foo() = this is T
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
public class JavaClass {
|
||||||
|
|
||||||
|
public static String nullString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String nonnullString() {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
fun box(): String {
|
||||||
|
val nullStr = JavaClass.nullString()
|
||||||
|
val nonnullStr = JavaClass.nonnullString()
|
||||||
|
|
||||||
|
if (nullStr.foo() != null) return "fail 1"
|
||||||
|
if (nonnullStr.foo() != nonnullStr) return "fail 2"
|
||||||
|
|
||||||
|
if (nullStr.fooN() != null) return "fail 3"
|
||||||
|
if (nonnullStr.fooN() != nonnullStr) return "fail 4"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> T.foo(): T = this as T
|
||||||
|
|
||||||
|
inline fun <reified T> T.fooN(): T? = this as T?
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
public class JavaClass {
|
||||||
|
|
||||||
|
public static String nullString() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String nonnullString() {
|
||||||
|
return "OK";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
fun box(): String {
|
||||||
|
val nullStr = JavaClass.nullString()
|
||||||
|
val nonnullStr = JavaClass.nonnullString()
|
||||||
|
|
||||||
|
if (nullStr.foo() != true) return "fail 1"
|
||||||
|
if (nonnullStr.foo() != true) return "fail 2"
|
||||||
|
|
||||||
|
if (nullStr.fooN() != true) return "fail 3"
|
||||||
|
if (nonnullStr.fooN() != true) return "fail 4"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> T.foo(): Boolean = this is T
|
||||||
|
|
||||||
|
inline fun <reified T> T.fooN(): Boolean = this is T?
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
inline fun <reified T> Any?.foo() = this as T
|
||||||
|
|
||||||
|
inline fun <reified Y> Any?.foo2() = foo<Y?>()
|
||||||
|
|
||||||
|
inline fun <reified Z> Any?.foo3() = foo2<Z>()
|
||||||
|
|
||||||
|
inline fun <reified X> Any?.foo4() = foo2<X?>()
|
||||||
|
|
||||||
|
inline fun <reified A> Any?.foo5() = foo<A>()
|
||||||
|
|
||||||
|
// 1 LDC "T"
|
||||||
|
// 1 LDC "Y\?"
|
||||||
|
// 1 LDC "Z\?"
|
||||||
|
// 1 LDC "X\?"
|
||||||
|
// 1 LDC "A"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
inline fun <reified T> Any?.foo() = this as T?
|
||||||
|
|
||||||
|
inline fun <reified Y> Any?.foo2() = foo<Y?>()
|
||||||
|
|
||||||
|
inline fun <reified Z> Any?.foo3() = foo2<Z>()
|
||||||
|
|
||||||
|
inline fun <reified X> Any?.foo4() = foo2<X?>()
|
||||||
|
|
||||||
|
inline fun <reified A> Any?.foo5() = foo<A>()
|
||||||
|
|
||||||
|
// 1 LDC "T\?"
|
||||||
|
// 1 LDC "Y\?"
|
||||||
|
// 1 LDC "Z\?"
|
||||||
|
// 1 LDC "X\?"
|
||||||
|
// 1 LDC "A\?"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
inline fun <reified T> Any?.foo() = this is T
|
||||||
|
|
||||||
|
inline fun <reified Y> Any?.foo2() = foo<Y?>()
|
||||||
|
|
||||||
|
inline fun <reified Z> Any?.foo3() = foo2<Z>()
|
||||||
|
|
||||||
|
inline fun <reified X> Any?.foo4() = foo2<X?>()
|
||||||
|
|
||||||
|
inline fun <reified A> Any?.foo5() = foo<A>()
|
||||||
|
|
||||||
|
// 1 LDC "T"
|
||||||
|
// 1 LDC "Y\?"
|
||||||
|
// 1 LDC "Z\?"
|
||||||
|
// 1 LDC "X\?"
|
||||||
|
// 1 LDC "A"
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
inline fun <reified T> Any?.foo() = this is T?
|
||||||
|
|
||||||
|
inline fun <reified Y> Any?.foo2() = foo<Y?>()
|
||||||
|
|
||||||
|
inline fun <reified Z> Any?.foo3() = foo2<Z>()
|
||||||
|
|
||||||
|
inline fun <reified X> Any?.foo4() = foo2<X?>()
|
||||||
|
|
||||||
|
inline fun <reified A> Any?.foo5() = foo<A>()
|
||||||
|
|
||||||
|
// 1 LDC "T\?"
|
||||||
|
// 1 LDC "Y\?"
|
||||||
|
// 1 LDC "Z\?"
|
||||||
|
// 1 LDC "X\?"
|
||||||
|
// 1 LDC "A\?"
|
||||||
@@ -257,6 +257,30 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedAsCheck.kt")
|
||||||
|
public void testReifiedAsCheck() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/reifiedAsCheck.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedAsCheckWithNullable.kt")
|
||||||
|
public void testReifiedAsCheckWithNullable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/reifiedAsCheckWithNullable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedIsCheck.kt")
|
||||||
|
public void testReifiedIsCheck() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/reifiedIsCheck.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("reifiedIsCheckWithNullable.kt")
|
||||||
|
public void testReifiedIsCheckWithNullable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/reifiedIsCheckWithNullable.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("safeAsWithMutable.kt")
|
@TestMetadata("safeAsWithMutable.kt")
|
||||||
public void testSafeAsWithMutable() throws Exception {
|
public void testSafeAsWithMutable() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/safeAsWithMutable.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/safeAsWithMutable.kt");
|
||||||
|
|||||||
+72
@@ -1293,6 +1293,78 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
|
||||||
doTestMultiFileWithInlineCheck(fileName);
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/reified/checkCast")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class CheckCast extends AbstractBlackBoxInlineCodegenTest {
|
||||||
|
public void testAllFilesPresentInCheckCast() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/checkCast"), Pattern.compile("^(.+)\\.1.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("chain.1.kt")
|
||||||
|
public void testChain() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/chain.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt8043.1.kt")
|
||||||
|
public void testKt8043() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/kt8043.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("maxStack.1.kt")
|
||||||
|
public void testMaxStack() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/maxStack.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullable.1.kt")
|
||||||
|
public void testNullable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/nullable.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.1.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/simple.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleSafe.1.kt")
|
||||||
|
public void testSimpleSafe() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/simpleSafe.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/reified/isCheck")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IsCheck extends AbstractBlackBoxInlineCodegenTest {
|
||||||
|
public void testAllFilesPresentInIsCheck() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/isCheck"), Pattern.compile("^(.+)\\.1.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("chain.1.kt")
|
||||||
|
public void testChain() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/isCheck/chain.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullable.1.kt")
|
||||||
|
public void testNullable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/isCheck/nullable.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.1.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/isCheck/simple.1.kt");
|
||||||
|
doTestMultiFileWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/simple")
|
@TestMetadata("compiler/testData/codegen/boxInline/simple")
|
||||||
|
|||||||
+22
@@ -673,6 +673,28 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxWithJava/reified")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class Reified extends AbstractBlackBoxCodegenTest {
|
||||||
|
public void testAllFilesPresentInReified() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithJava/reified"), Pattern.compile("^([^\\.]+)$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("asCheck")
|
||||||
|
public void testAsCheck() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reified/asCheck/");
|
||||||
|
doTestWithJava(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("isCheck")
|
||||||
|
public void testIsCheck() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/reified/isCheck/");
|
||||||
|
doTestWithJava(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxWithJava/secondaryConstructors")
|
@TestMetadata("compiler/testData/codegen/boxWithJava/secondaryConstructors")
|
||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
|||||||
+72
@@ -1293,6 +1293,78 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/packages.1.kt");
|
||||||
doBoxTestWithInlineCheck(fileName);
|
doBoxTestWithInlineCheck(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/reified/checkCast")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class CheckCast extends AbstractCompileKotlinAgainstInlineKotlinTest {
|
||||||
|
public void testAllFilesPresentInCheckCast() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/checkCast"), Pattern.compile("^(.+)\\.1.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("chain.1.kt")
|
||||||
|
public void testChain() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/chain.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt8043.1.kt")
|
||||||
|
public void testKt8043() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/kt8043.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("maxStack.1.kt")
|
||||||
|
public void testMaxStack() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/maxStack.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullable.1.kt")
|
||||||
|
public void testNullable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/nullable.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.1.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/simple.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simpleSafe.1.kt")
|
||||||
|
public void testSimpleSafe() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/checkCast/simpleSafe.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("compiler/testData/codegen/boxInline/reified/isCheck")
|
||||||
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
|
public static class IsCheck extends AbstractCompileKotlinAgainstInlineKotlinTest {
|
||||||
|
public void testAllFilesPresentInIsCheck() throws Exception {
|
||||||
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxInline/reified/isCheck"), Pattern.compile("^(.+)\\.1.kt$"), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("chain.1.kt")
|
||||||
|
public void testChain() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/isCheck/chain.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nullable.1.kt")
|
||||||
|
public void testNullable() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/isCheck/nullable.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("simple.1.kt")
|
||||||
|
public void testSimple() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/reified/isCheck/simple.1.kt");
|
||||||
|
doBoxTestWithInlineCheck(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxInline/simple")
|
@TestMetadata("compiler/testData/codegen/boxInline/simple")
|
||||||
|
|||||||
Reference in New Issue
Block a user