Throw NPE instead of TypeCastException since 1.4

#KT-22275 In Progress
This commit is contained in:
Alexander Udalov
2019-08-06 11:21:48 +02:00
parent 2baddb029c
commit e207c96336
9 changed files with 48 additions and 13 deletions
@@ -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)
@@ -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)
+13
View File
@@ -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"
}
}
@@ -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");
@@ -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");
@@ -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");