Throw NPE instead of TypeCastException since 1.4
#KT-22275 In Progress
This commit is contained in:
@@ -4773,8 +4773,7 @@ The "returned" value of try expression with no finally is either the last expres
|
|||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
CodegenUtilKt.generateAsCast(v, rightKotlinType, boxedRightType, safeAs,
|
CodegenUtilKt.generateAsCast(v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings());
|
||||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
|
|
||||||
|
|
||||||
return Unit.INSTANCE;
|
return Unit.INSTANCE;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ import org.jetbrains.kotlin.codegen.intrinsics.TypeIntrinsics
|
|||||||
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
import org.jetbrains.kotlin.codegen.optimization.common.asSequence
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
|
import org.jetbrains.kotlin.config.ApiVersion
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
import org.jetbrains.kotlin.descriptors.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
@@ -98,16 +101,16 @@ fun generateAsCast(
|
|||||||
kotlinType: KotlinType,
|
kotlinType: KotlinType,
|
||||||
asmType: Type,
|
asmType: Type,
|
||||||
isSafe: Boolean,
|
isSafe: Boolean,
|
||||||
isReleaseCoroutines: Boolean
|
languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
if (!isSafe) {
|
if (!isSafe) {
|
||||||
if (!TypeUtils.isNullableType(kotlinType)) {
|
if (!TypeUtils.isNullableType(kotlinType)) {
|
||||||
generateNullCheckForNonSafeAs(v, kotlinType)
|
generateNullCheckForNonSafeAs(v, kotlinType, languageVersionSettings)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
with(v) {
|
with(v) {
|
||||||
dup()
|
dup()
|
||||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
|
TypeIntrinsics.instanceOf(v, kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
|
||||||
val ok = Label()
|
val ok = Label()
|
||||||
ifne(ok)
|
ifne(ok)
|
||||||
pop()
|
pop()
|
||||||
@@ -121,15 +124,19 @@ fun generateAsCast(
|
|||||||
|
|
||||||
private fun generateNullCheckForNonSafeAs(
|
private fun generateNullCheckForNonSafeAs(
|
||||||
v: InstructionAdapter,
|
v: InstructionAdapter,
|
||||||
type: KotlinType
|
type: KotlinType,
|
||||||
|
languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
with(v) {
|
with(v) {
|
||||||
dup()
|
dup()
|
||||||
val nonnull = Label()
|
val nonnull = Label()
|
||||||
ifnonnull(nonnull)
|
ifnonnull(nonnull)
|
||||||
|
val exceptionClass =
|
||||||
|
if (languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) "java/lang/NullPointerException"
|
||||||
|
else "kotlin/TypeCastException"
|
||||||
AsmUtil.genThrow(
|
AsmUtil.genThrow(
|
||||||
v,
|
v,
|
||||||
"kotlin/TypeCastException",
|
exceptionClass,
|
||||||
"null cannot be cast to non-null type " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type)
|
"null cannot be cast to non-null type " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type)
|
||||||
)
|
)
|
||||||
mark(nonnull)
|
mark(nonnull)
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
private val initialFrameSize = codegen.frameMap.currentSize
|
private val initialFrameSize = codegen.frameMap.currentSize
|
||||||
|
|
||||||
private val reifiedTypeInliner =
|
private val reifiedTypeInliner =
|
||||||
ReifiedTypeInliner(typeParameterMappings, state.typeMapper, state.languageVersionSettings.isReleaseCoroutines())
|
ReifiedTypeInliner(typeParameterMappings, state.typeMapper, state.languageVersionSettings)
|
||||||
|
|
||||||
protected val functionDescriptor: FunctionDescriptor =
|
protected val functionDescriptor: FunctionDescriptor =
|
||||||
if (InlineUtil.isArrayConstructorWithLambda(function))
|
if (InlineUtil.isArrayConstructorWithLambda(function))
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.codegen.generateIsCheck
|
|||||||
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods
|
||||||
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
|
import org.jetbrains.kotlin.codegen.optimization.common.intConstant
|
||||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
|
import org.jetbrains.kotlin.config.isReleaseCoroutines
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
@@ -65,7 +67,7 @@ class ReificationArgument(
|
|||||||
class ReifiedTypeInliner(
|
class ReifiedTypeInliner(
|
||||||
private val parametersMapping: TypeParameterMappings?,
|
private val parametersMapping: TypeParameterMappings?,
|
||||||
private val typeMapper: KotlinTypeMapper,
|
private val typeMapper: KotlinTypeMapper,
|
||||||
private val isReleaseCoroutines: Boolean
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
enum class OperationKind {
|
enum class OperationKind {
|
||||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF;
|
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF;
|
||||||
@@ -188,7 +190,7 @@ class ReifiedTypeInliner(
|
|||||||
if (stubCheckcast !is TypeInsnNode) return false
|
if (stubCheckcast !is TypeInsnNode) return false
|
||||||
|
|
||||||
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
||||||
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, isReleaseCoroutines)
|
generateAsCast(InstructionAdapter(newMethodNode), kotlinType, asmType, safe, languageVersionSettings)
|
||||||
|
|
||||||
instructions.insert(insn, newMethodNode.instructions)
|
instructions.insert(insn, newMethodNode.instructions)
|
||||||
instructions.remove(stubCheckcast)
|
instructions.remove(stubCheckcast)
|
||||||
@@ -208,7 +210,7 @@ class ReifiedTypeInliner(
|
|||||||
if (stubInstanceOf !is TypeInsnNode) return false
|
if (stubInstanceOf !is TypeInsnNode) return false
|
||||||
|
|
||||||
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
val newMethodNode = MethodNode(Opcodes.API_VERSION)
|
||||||
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType, isReleaseCoroutines)
|
generateIsCheck(InstructionAdapter(newMethodNode), kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
|
||||||
|
|
||||||
instructions.insert(insn, newMethodNode.instructions)
|
instructions.insert(insn, newMethodNode.instructions)
|
||||||
instructions.remove(stubInstanceOf)
|
instructions.remove(stubInstanceOf)
|
||||||
|
|||||||
+1
-2
@@ -782,8 +782,7 @@ class ExpressionCodegen(
|
|||||||
v.checkcast(boxedRightType)
|
v.checkcast(boxedRightType)
|
||||||
} else {
|
} else {
|
||||||
generateAsCast(
|
generateAsCast(
|
||||||
mv, kotlinType, boxedRightType, expression.operator == IrTypeOperator.SAFE_CAST,
|
mv, kotlinType, boxedRightType, expression.operator == IrTypeOperator.SAFE_CAST, state.languageVersionSettings
|
||||||
state.languageVersionSettings.isReleaseCoroutines()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
MaterialValue(this, boxedRightType, expression.type).coerce(expression.type)
|
MaterialValue(this, boxedRightType, expression.type).coerce(expression.type)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// !API_VERSION: LATEST
|
||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val s: String? = null
|
||||||
|
try {
|
||||||
|
s as String
|
||||||
|
return "Fail: NPE should have been thrown"
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
if (e::class != NullPointerException::class) return "Fail: exception class should be NPE: ${e::class}"
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
+5
@@ -2696,6 +2696,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/casts/asSafeForConstants.kt");
|
runTest("compiler/testData/codegen/box/casts/asSafeForConstants.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("asThrowsNpe_1_4.kt")
|
||||||
|
public void testAsThrowsNpe_1_4() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/asThrowsNpe_1_4.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("asUnit.kt")
|
@TestMetadata("asUnit.kt")
|
||||||
public void testAsUnit() throws Exception {
|
public void testAsUnit() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
||||||
|
|||||||
+5
@@ -2696,6 +2696,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
runTest("compiler/testData/codegen/box/casts/asSafeForConstants.kt");
|
runTest("compiler/testData/codegen/box/casts/asSafeForConstants.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("asThrowsNpe_1_4.kt")
|
||||||
|
public void testAsThrowsNpe_1_4() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/asThrowsNpe_1_4.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("asUnit.kt")
|
@TestMetadata("asUnit.kt")
|
||||||
public void testAsUnit() throws Exception {
|
public void testAsUnit() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
||||||
|
|||||||
+5
@@ -2676,6 +2676,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/casts/asSafeForConstants.kt");
|
runTest("compiler/testData/codegen/box/casts/asSafeForConstants.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("asThrowsNpe_1_4.kt")
|
||||||
|
public void testAsThrowsNpe_1_4() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/casts/asThrowsNpe_1_4.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("asUnit.kt")
|
@TestMetadata("asUnit.kt")
|
||||||
public void testAsUnit() throws Exception {
|
public void testAsUnit() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user