Don't recognize nullable function types as inlinable
#KT-19679 Fixed
This commit is contained in:
@@ -529,7 +529,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
|||||||
val varDescriptor = field.descriptor
|
val varDescriptor = field.descriptor
|
||||||
//check that variable is inline function parameter
|
//check that variable is inline function parameter
|
||||||
return !(varDescriptor is ParameterDescriptor &&
|
return !(varDescriptor is ParameterDescriptor &&
|
||||||
InlineUtil.isInlineLambdaParameter(varDescriptor) &&
|
InlineUtil.isInlineParameter(varDescriptor) &&
|
||||||
InlineUtil.isInline(varDescriptor.containingDeclaration))
|
InlineUtil.isInline(varDescriptor.containingDeclaration))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -631,7 +631,7 @@ class PsiInlineCodegen(
|
|||||||
//TODO deparenthisise typed
|
//TODO deparenthisise typed
|
||||||
val deparenthesized = KtPsiUtil.deparenthesize(expression)
|
val deparenthesized = KtPsiUtil.deparenthesize(expression)
|
||||||
|
|
||||||
return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
|
return InlineUtil.isInlineParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun genValueAndPut(
|
override fun genValueAndPut(
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ fun extractDefaultLambdaOffsetAndDescriptor(jvmSignature: JvmMethodSignature, fu
|
|||||||
val valueParameterOffset = valueParameters.takeWhile { it.kind != JvmMethodParameterKind.VALUE }.size
|
val valueParameterOffset = valueParameters.takeWhile { it.kind != JvmMethodParameterKind.VALUE }.size
|
||||||
|
|
||||||
return functionDescriptor.valueParameters.filter {
|
return functionDescriptor.valueParameters.filter {
|
||||||
InlineUtil.isInlineLambdaParameter(it) && it.declaresDefaultValue()
|
InlineUtil.isInlineParameter(it) && it.declaresDefaultValue()
|
||||||
}.associateBy {
|
}.associateBy {
|
||||||
parameterOffsets[valueParameterOffset + it.index]
|
parameterOffsets[valueParameterOffset + it.index]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC
|
|||||||
|
|
||||||
private val isEffectivelyPrivateApiFunction = descriptor.isEffectivelyPrivateApi
|
private val isEffectivelyPrivateApiFunction = descriptor.isEffectivelyPrivateApi
|
||||||
|
|
||||||
private val inlinableParameters = descriptor.valueParameters.filter { isInlinableParameter(it) }
|
private val inlinableParameters = descriptor.valueParameters.filter { InlineUtil.isInlineParameter(it) }
|
||||||
|
|
||||||
private val inlinableKtParameters = inlinableParameters.mapNotNull { (it.source as? KotlinSourceElement)?.psi }
|
private val inlinableKtParameters = inlinableParameters.mapNotNull { (it.source as? KotlinSourceElement)?.psi }
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC
|
|||||||
when {
|
when {
|
||||||
!checkNotInDefaultParameter(context, argumentCallee, argumentExpression) -> { /*error*/ }
|
!checkNotInDefaultParameter(context, argumentCallee, argumentExpression) -> { /*error*/ }
|
||||||
|
|
||||||
InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor) ->
|
InlineUtil.isInline(targetDescriptor) && InlineUtil.isInlineParameter(targetParameterDescriptor) ->
|
||||||
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
|
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
|
||||||
context.trace.report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression))
|
context.trace.report(NON_LOCAL_RETURN_NOT_ALLOWED.on(argumentExpression, argumentExpression))
|
||||||
}
|
}
|
||||||
@@ -219,10 +219,6 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isInlinableParameter(descriptor: ParameterDescriptor): Boolean {
|
|
||||||
return InlineUtil.isInlineLambdaParameter(descriptor) && !descriptor.type.isMarkedNullable
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isInvokeOrInlineExtension(descriptor: CallableDescriptor): Boolean {
|
private fun isInvokeOrInlineExtension(descriptor: CallableDescriptor): Boolean {
|
||||||
if (descriptor !is SimpleFunctionDescriptor) {
|
if (descriptor !is SimpleFunctionDescriptor) {
|
||||||
return false
|
return false
|
||||||
|
|||||||
+6
-3
@@ -154,9 +154,12 @@ class InlineAnalyzerExtension(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkHasInlinableAndNullability(functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) {
|
private fun checkHasInlinableAndNullability(functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) {
|
||||||
for ((parameter, descriptor) in function.valueParameters.zip(functionDescriptor.valueParameters)) {
|
var hasInlineArgs = false
|
||||||
if (checkInlinableParameter(descriptor, parameter, functionDescriptor, trace)) return
|
function.valueParameters.zip(functionDescriptor.valueParameters).forEach {
|
||||||
|
(parameter, descriptor) ->
|
||||||
|
hasInlineArgs = hasInlineArgs or checkInlinableParameter(descriptor, parameter, functionDescriptor, trace)
|
||||||
}
|
}
|
||||||
|
if (hasInlineArgs) return
|
||||||
|
|
||||||
if (functionDescriptor.isInlineOnlyOrReifiable() || functionDescriptor.isHeader) return
|
if (functionDescriptor.isInlineOnlyOrReifiable() || functionDescriptor.isHeader) return
|
||||||
|
|
||||||
@@ -171,7 +174,7 @@ class InlineAnalyzerExtension(
|
|||||||
expression: KtElement,
|
expression: KtElement,
|
||||||
functionDescriptor: CallableDescriptor,
|
functionDescriptor: CallableDescriptor,
|
||||||
trace: BindingTrace?): Boolean {
|
trace: BindingTrace?): Boolean {
|
||||||
if (InlineUtil.isInlineLambdaParameter(parameter)) {
|
if (InlineUtil.isInlineParameterExceptNullability(parameter)) {
|
||||||
if (parameter.type.isMarkedNullable) {
|
if (parameter.type.isMarkedNullable) {
|
||||||
trace?.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor))
|
trace?.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,18 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch;
|
|||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||||
|
|
||||||
public class InlineUtil {
|
public class InlineUtil {
|
||||||
public static boolean isInlineLambdaParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) {
|
|
||||||
|
public static boolean isInlineParameterExceptNullability(@NotNull ParameterDescriptor valueParameterOrReceiver) {
|
||||||
return !(valueParameterOrReceiver instanceof ValueParameterDescriptor
|
return !(valueParameterOrReceiver instanceof ValueParameterDescriptor
|
||||||
&& ((ValueParameterDescriptor) valueParameterOrReceiver).isNoinline()) &&
|
&& ((ValueParameterDescriptor) valueParameterOrReceiver).isNoinline()) &&
|
||||||
FunctionTypesKt.isFunctionType(valueParameterOrReceiver.getOriginal().getType());
|
FunctionTypesKt.isFunctionType(valueParameterOrReceiver.getOriginal().getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isInlineParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) {
|
||||||
|
return isInlineParameterExceptNullability(valueParameterOrReceiver) &&
|
||||||
|
!valueParameterOrReceiver.getOriginal().getType().isMarkedNullable();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isInline(@Nullable DeclarationDescriptor descriptor) {
|
public static boolean isInline(@Nullable DeclarationDescriptor descriptor) {
|
||||||
return descriptor instanceof FunctionDescriptor && getInlineStrategy((FunctionDescriptor) descriptor).isInline();
|
return descriptor instanceof FunctionDescriptor && getInlineStrategy((FunctionDescriptor) descriptor).isInline();
|
||||||
}
|
}
|
||||||
@@ -152,7 +158,7 @@ public class InlineUtil {
|
|||||||
if (!(mapping instanceof ArgumentMatch)) return null;
|
if (!(mapping instanceof ArgumentMatch)) return null;
|
||||||
|
|
||||||
ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter();
|
ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter();
|
||||||
return isInlineLambdaParameter(parameter) ? parameter : null;
|
return isInlineParameter(parameter) ? parameter : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean canBeInlineArgument(@Nullable PsiElement functionalExpression) {
|
public static boolean canBeInlineArgument(@Nullable PsiElement functionalExpression) {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
package test
|
||||||
|
|
||||||
|
inline fun build(func: () -> Unit, noinline pathFunc: (() -> String)? = null) {
|
||||||
|
func()
|
||||||
|
|
||||||
|
pathFunc?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = "fail"
|
||||||
|
build({ result = "OK" })
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
package test
|
||||||
|
|
||||||
|
inline fun build(noinline pathFunc: (() -> String)? = null) {
|
||||||
|
pathFunc?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
build ()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
// FILE: 1.kt
|
||||||
|
package test
|
||||||
|
|
||||||
|
@Suppress("NULLABLE_INLINE_PARAMETER")
|
||||||
|
inline fun build(func: () -> Unit, pathFunc: (() -> String)? = null) {
|
||||||
|
func()
|
||||||
|
|
||||||
|
pathFunc?.invoke()
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: 2.kt
|
||||||
|
|
||||||
|
import test.*
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var result = "fail"
|
||||||
|
build ({ result = "OK" })
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
inline fun test(s: () -> Unit, <!NULLABLE_INLINE_PARAMETER!>p: (() -> Unit)?<!>) {
|
||||||
|
s()
|
||||||
|
p?.invoke()
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
public inline fun test(/*0*/ s: () -> kotlin.Unit, /*1*/ p: (() -> kotlin.Unit)?): kotlin.Unit
|
||||||
+18
@@ -1339,6 +1339,24 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679.kt")
|
||||||
|
public void testKt19679() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_2.kt")
|
||||||
|
public void testKt19679_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_3.kt")
|
||||||
|
public void testKt19679_3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
||||||
|
|||||||
+18
@@ -1339,6 +1339,24 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679.kt")
|
||||||
|
public void testKt19679() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_2.kt")
|
||||||
|
public void testKt19679_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_3.kt")
|
||||||
|
public void testKt19679_3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
||||||
|
|||||||
@@ -11263,6 +11263,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679.kt")
|
||||||
|
public void testKt19679() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inline/kt19679.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt4869.kt")
|
@TestMetadata("kt4869.kt")
|
||||||
public void testKt4869() throws Exception {
|
public void testKt4869() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inline/kt4869.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inline/kt4869.kt");
|
||||||
|
|||||||
@@ -1339,6 +1339,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679.kt")
|
||||||
|
public void testKt19679() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_2.kt")
|
||||||
|
public void testKt19679_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_3.kt")
|
||||||
|
public void testKt19679_3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
||||||
|
|||||||
+18
@@ -1339,6 +1339,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679.kt")
|
||||||
|
public void testKt19679() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_2.kt")
|
||||||
|
public void testKt19679_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_3.kt")
|
||||||
|
public void testKt19679_3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
||||||
|
|||||||
+18
@@ -416,6 +416,24 @@ public class InlineDefaultValuesTestsGenerated extends AbstractInlineDefaultValu
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679.kt")
|
||||||
|
public void testKt19679() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_2.kt")
|
||||||
|
public void testKt19679_2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt19679_3.kt")
|
||||||
|
public void testKt19679_3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/kt19679_3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");
|
||||||
|
|||||||
+1
-1
@@ -79,7 +79,7 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
|
|||||||
|
|
||||||
if (descriptor instanceof ValueParameterDescriptor) {
|
if (descriptor instanceof ValueParameterDescriptor) {
|
||||||
return InlineUtil.isInline(descriptor.getContainingDeclaration()) &&
|
return InlineUtil.isInline(descriptor.getContainingDeclaration()) &&
|
||||||
InlineUtil.isInlineLambdaParameter((ParameterDescriptor) descriptor) &&
|
InlineUtil.isInlineParameter((ParameterDescriptor) descriptor) &&
|
||||||
!((ValueParameterDescriptor) descriptor).isCrossinline();
|
!((ValueParameterDescriptor) descriptor).isCrossinline();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user