Avoid non-null assertions for inline classes based on nullable types
Note that there are more places where assertions for inline classes should refined: - lateinit vars - values that come from Java - type casts (interfaces to inline class type)
This commit is contained in:
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.name.FqName;
|
|||||||
import org.jetbrains.kotlin.protobuf.MessageLite;
|
import org.jetbrains.kotlin.protobuf.MessageLite;
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
|
import org.jetbrains.kotlin.resolve.InlineClassesUtilsKt;
|
||||||
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil;
|
||||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
import org.jetbrains.kotlin.resolve.jvm.JvmClassName;
|
||||||
@@ -683,7 +684,7 @@ public class AsmUtil {
|
|||||||
@NotNull String name
|
@NotNull String name
|
||||||
) {
|
) {
|
||||||
KotlinType type = parameter.getType();
|
KotlinType type = parameter.getType();
|
||||||
if (isNullableType(type)) return;
|
if (isNullableType(type) || InlineClassesUtilsKt.isNullableUnderlyingType(type)) return;
|
||||||
|
|
||||||
int index = frameMap.getIndex(parameter);
|
int index = frameMap.getIndex(parameter);
|
||||||
Type asmType = typeMapper.mapType(type);
|
Type asmType = typeMapper.mapType(type);
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010-2016 JetBrains s.r.o.
|
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
*
|
* that can be found in the license/LICENSE.txt file.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.resolve.jvm
|
package org.jetbrains.kotlin.resolve.jvm
|
||||||
@@ -30,6 +19,7 @@ import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker
|
|||||||
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.isNullableUnderlyingType
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
@@ -62,7 +52,12 @@ class RuntimeAssertionInfo(val needNotNullAssertion: Boolean, val message: Strin
|
|||||||
// Cases when nullability assertion needed: T! -> T, T$ -> T
|
// Cases when nullability assertion needed: T! -> T, T$ -> T
|
||||||
|
|
||||||
// Expected type either T?, T! or T$
|
// Expected type either T?, T! or T$
|
||||||
if (TypeUtils.isNullableType(expectedType) || expectedType.hasEnhancedNullability()) return false
|
if (TypeUtils.isNullableType(expectedType) ||
|
||||||
|
expectedType.hasEnhancedNullability() ||
|
||||||
|
expectedType.isNullableUnderlyingType()
|
||||||
|
) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Expression type is not nullable and not enhanced (neither T?, T! or T$)
|
// Expression type is not nullable and not enhanced (neither T?, T! or T$)
|
||||||
val isExpressionTypeNullable = TypeUtils.isNullableType(expressionType)
|
val isExpressionTypeNullable = TypeUtils.isNullableType(expressionType)
|
||||||
|
|||||||
Vendored
+38
@@ -0,0 +1,38 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
|
inline class Result<T>(val a: Any?)
|
||||||
|
|
||||||
|
fun resultOfIntToResultOfInt(r: Result<Int>): Result<Int> {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> idResult(r: Result<T>): Result<T> = r
|
||||||
|
|
||||||
|
fun Result<Int>.extension(): Result<Int> = this
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val r = Result<Int>(null)
|
||||||
|
|
||||||
|
resultOfIntToResultOfInt(r)
|
||||||
|
resultOfIntToResultOfInt(Result<Int>(null))
|
||||||
|
|
||||||
|
val nonNull1 = resultOfIntToResultOfInt(r)
|
||||||
|
val nonNull2 = resultOfIntToResultOfInt(Result<Int>(null))
|
||||||
|
|
||||||
|
resultOfIntToResultOfInt(nonNull1)
|
||||||
|
|
||||||
|
if (nonNull1.a != null) return "fail"
|
||||||
|
if (nonNull2.a != null) return "fail"
|
||||||
|
|
||||||
|
if (resultOfIntToResultOfInt(r).a != null) return "fail"
|
||||||
|
|
||||||
|
idResult(Result<String>(null))
|
||||||
|
|
||||||
|
val id = idResult(r)
|
||||||
|
if (id.a != null) return "fail"
|
||||||
|
|
||||||
|
r.extension()
|
||||||
|
Result<Int>(null).extension()
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
Vendored
+14
@@ -0,0 +1,14 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
|
inline class AsNonNullPrimitive(val i: Int)
|
||||||
|
inline class AsNonNullReference(val s: String) // 2 assertions (constructor, box method)
|
||||||
|
|
||||||
|
fun nonNullPrimitive(a: AsNonNullPrimitive) {}
|
||||||
|
|
||||||
|
fun nonNullReference(b: AsNonNullReference) {} // assertion
|
||||||
|
fun AsNonNullReference.nonNullReferenceExtension(b1: AsNonNullReference) {} // 2 assertions
|
||||||
|
|
||||||
|
fun asNullablePrimitive(c: AsNonNullPrimitive?) {}
|
||||||
|
fun asNullableReference(c: AsNonNullReference?) {}
|
||||||
|
|
||||||
|
// 5 checkParameterIsNotNull
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
// !LANGUAGE: +InlineClasses
|
||||||
|
|
||||||
|
inline class AsAny(val a: Any?)
|
||||||
|
|
||||||
|
fun asNotNullAny(a: AsAny) {}
|
||||||
|
fun AsAny.asNotNullAnyExtension(b: AsAny): AsAny = this
|
||||||
|
|
||||||
|
// 0 checkParameterIsNotNull
|
||||||
Generated
+6
@@ -10653,6 +10653,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
|
||||||
|
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("passInlineClassAsVararg.kt")
|
@TestMetadata("passInlineClassAsVararg.kt")
|
||||||
public void testPassInlineClassAsVararg() throws Exception {
|
public void testPassInlineClassAsVararg() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
||||||
|
|||||||
+6
@@ -10653,6 +10653,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
|
||||||
|
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("passInlineClassAsVararg.kt")
|
@TestMetadata("passInlineClassAsVararg.kt")
|
||||||
public void testPassInlineClassAsVararg() throws Exception {
|
public void testPassInlineClassAsVararg() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
||||||
|
|||||||
@@ -1947,6 +1947,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("assertionsForParametersOfInlineClassTypes.kt")
|
||||||
|
public void testAssertionsForParametersOfInlineClassTypes() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/assertionsForParametersOfInlineClassTypes.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("boxInlineClassesOnPassingToVarargs.kt")
|
@TestMetadata("boxInlineClassesOnPassingToVarargs.kt")
|
||||||
public void testBoxInlineClassesOnPassingToVarargs() throws Exception {
|
public void testBoxInlineClassesOnPassingToVarargs() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/boxInlineClassesOnPassingToVarargs.kt");
|
||||||
@@ -2049,6 +2055,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noAssertionsForInlineClassesBasedOnNullableTypes.kt")
|
||||||
|
public void testNoAssertionsForInlineClassesBasedOnNullableTypes() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/noAssertionsForInlineClassesBasedOnNullableTypes.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("passInlineClassesWithSpreadOperatorToVarargs.kt")
|
@TestMetadata("passInlineClassesWithSpreadOperatorToVarargs.kt")
|
||||||
public void testPassInlineClassesWithSpreadOperatorToVarargs() throws Exception {
|
public void testPassInlineClassesWithSpreadOperatorToVarargs() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/inlineClasses/passInlineClassesWithSpreadOperatorToVarargs.kt");
|
||||||
|
|||||||
+6
@@ -10653,6 +10653,12 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
|
||||||
|
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("passInlineClassAsVararg.kt")
|
@TestMetadata("passInlineClassAsVararg.kt")
|
||||||
public void testPassInlineClassAsVararg() throws Exception {
|
public void testPassInlineClassAsVararg() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
fun ClassDescriptor.underlyingRepresentation(): ValueParameterDescriptor? {
|
fun ClassDescriptor.underlyingRepresentation(): ValueParameterDescriptor? {
|
||||||
@@ -30,4 +31,11 @@ fun KotlinType.isInlineClassType(): Boolean = constructor.declarationDescriptor?
|
|||||||
fun KotlinType.substitutedUnderlyingType(): KotlinType? {
|
fun KotlinType.substitutedUnderlyingType(): KotlinType? {
|
||||||
val parameter = unsubstitutedUnderlyingParameter() ?: return null
|
val parameter = unsubstitutedUnderlyingParameter() ?: return null
|
||||||
return memberScope.getContributedVariables(parameter.name, NoLookupLocation.FOR_ALREADY_TRACKED).singleOrNull()?.type
|
return memberScope.getContributedVariables(parameter.name, NoLookupLocation.FOR_ALREADY_TRACKED).singleOrNull()?.type
|
||||||
|
}
|
||||||
|
|
||||||
|
fun KotlinType.isNullableUnderlyingType(): Boolean {
|
||||||
|
if (!isInlineClassType()) return false
|
||||||
|
val underlyingType = unsubstitutedUnderlyingType() ?: return false
|
||||||
|
|
||||||
|
return TypeUtils.isNullableType(underlyingType)
|
||||||
}
|
}
|
||||||
+6
@@ -11715,6 +11715,12 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("noAssertionsOnInlineClassBasedOnNullableType.kt")
|
||||||
|
public void testNoAssertionsOnInlineClassBasedOnNullableType() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/noAssertionsOnInlineClassBasedOnNullableType.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("passInlineClassAsVararg.kt")
|
@TestMetadata("passInlineClassAsVararg.kt")
|
||||||
public void testPassInlineClassAsVararg() throws Exception {
|
public void testPassInlineClassAsVararg() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/inlineClasses/passInlineClassAsVararg.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user