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;
|
||||
}
|
||||
|
||||
CodegenUtilKt.generateAsCast(v, rightKotlinType, boxedRightType, safeAs,
|
||||
state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
|
||||
CodegenUtilKt.generateAsCast(v, rightKotlinType, boxedRightType, safeAs, state.getLanguageVersionSettings());
|
||||
|
||||
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.state.GenerationState
|
||||
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.deserialization.PLATFORM_DEPENDENT_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
@@ -98,16 +101,16 @@ fun generateAsCast(
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
isSafe: Boolean,
|
||||
isReleaseCoroutines: Boolean
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
if (!isSafe) {
|
||||
if (!TypeUtils.isNullableType(kotlinType)) {
|
||||
generateNullCheckForNonSafeAs(v, kotlinType)
|
||||
generateNullCheckForNonSafeAs(v, kotlinType, languageVersionSettings)
|
||||
}
|
||||
} else {
|
||||
with(v) {
|
||||
dup()
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, languageVersionSettings.isReleaseCoroutines())
|
||||
val ok = Label()
|
||||
ifne(ok)
|
||||
pop()
|
||||
@@ -121,15 +124,19 @@ fun generateAsCast(
|
||||
|
||||
private fun generateNullCheckForNonSafeAs(
|
||||
v: InstructionAdapter,
|
||||
type: KotlinType
|
||||
type: KotlinType,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
with(v) {
|
||||
dup()
|
||||
val nonnull = Label()
|
||||
ifnonnull(nonnull)
|
||||
val exceptionClass =
|
||||
if (languageVersionSettings.apiVersion >= ApiVersion.KOTLIN_1_4) "java/lang/NullPointerException"
|
||||
else "kotlin/TypeCastException"
|
||||
AsmUtil.genThrow(
|
||||
v,
|
||||
"kotlin/TypeCastException",
|
||||
exceptionClass,
|
||||
"null cannot be cast to non-null type " + DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(type)
|
||||
)
|
||||
mark(nonnull)
|
||||
|
||||
@@ -74,7 +74,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
||||
private val initialFrameSize = codegen.frameMap.currentSize
|
||||
|
||||
private val reifiedTypeInliner =
|
||||
ReifiedTypeInliner(typeParameterMappings, state.typeMapper, state.languageVersionSettings.isReleaseCoroutines())
|
||||
ReifiedTypeInliner(typeParameterMappings, state.typeMapper, state.languageVersionSettings)
|
||||
|
||||
protected val functionDescriptor: FunctionDescriptor =
|
||||
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.optimization.common.intConstant
|
||||
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.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -65,7 +67,7 @@ class ReificationArgument(
|
||||
class ReifiedTypeInliner(
|
||||
private val parametersMapping: TypeParameterMappings?,
|
||||
private val typeMapper: KotlinTypeMapper,
|
||||
private val isReleaseCoroutines: Boolean
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
enum class OperationKind {
|
||||
NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS, ENUM_REIFIED, TYPE_OF;
|
||||
@@ -188,7 +190,7 @@ class ReifiedTypeInliner(
|
||||
if (stubCheckcast !is TypeInsnNode) return false
|
||||
|
||||
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.remove(stubCheckcast)
|
||||
@@ -208,7 +210,7 @@ class ReifiedTypeInliner(
|
||||
if (stubInstanceOf !is TypeInsnNode) return false
|
||||
|
||||
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.remove(stubInstanceOf)
|
||||
|
||||
+1
-2
@@ -782,8 +782,7 @@ class ExpressionCodegen(
|
||||
v.checkcast(boxedRightType)
|
||||
} else {
|
||||
generateAsCast(
|
||||
mv, kotlinType, boxedRightType, expression.operator == IrTypeOperator.SAFE_CAST,
|
||||
state.languageVersionSettings.isReleaseCoroutines()
|
||||
mv, kotlinType, boxedRightType, expression.operator == IrTypeOperator.SAFE_CAST, state.languageVersionSettings
|
||||
)
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testAsUnit() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testAsUnit() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testAsUnit() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/casts/asUnit.kt");
|
||||
|
||||
Reference in New Issue
Block a user