Don't recognize nullable function types as inlinable

#KT-19679 Fixed
This commit is contained in:
Mikhael Bogdanov
2017-08-16 12:51:28 +02:00
parent 1b2e28d467
commit 79ecc7fd5c
17 changed files with 177 additions and 15 deletions

View File

@@ -529,7 +529,7 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
val varDescriptor = field.descriptor
//check that variable is inline function parameter
return !(varDescriptor is ParameterDescriptor &&
InlineUtil.isInlineLambdaParameter(varDescriptor) &&
InlineUtil.isInlineParameter(varDescriptor) &&
InlineUtil.isInline(varDescriptor.containingDeclaration))
}
@@ -631,7 +631,7 @@ class PsiInlineCodegen(
//TODO deparenthisise typed
val deparenthesized = KtPsiUtil.deparenthesize(expression)
return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
return InlineUtil.isInlineParameter(valueParameterDescriptor) && isInlinableParameterExpression(deparenthesized)
}
override fun genValueAndPut(

View File

@@ -51,7 +51,7 @@ fun extractDefaultLambdaOffsetAndDescriptor(jvmSignature: JvmMethodSignature, fu
val valueParameterOffset = valueParameters.takeWhile { it.kind != JvmMethodParameterKind.VALUE }.size
return functionDescriptor.valueParameters.filter {
InlineUtil.isInlineLambdaParameter(it) && it.declaresDefaultValue()
InlineUtil.isInlineParameter(it) && it.declaresDefaultValue()
}.associateBy {
parameterOffsets[valueParameterOffset + it.index]
}

View File

@@ -51,7 +51,7 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC
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 }
@@ -132,7 +132,7 @@ internal class InlineChecker(private val descriptor: FunctionDescriptor) : CallC
when {
!checkNotInDefaultParameter(context, argumentCallee, argumentExpression) -> { /*error*/ }
InlineUtil.isInline(targetDescriptor) && isInlinableParameter(targetParameterDescriptor) ->
InlineUtil.isInline(targetDescriptor) && InlineUtil.isInlineParameter(targetParameterDescriptor) ->
if (allowsNonLocalReturns(argumentCallee) && !allowsNonLocalReturns(targetParameterDescriptor)) {
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 {
if (descriptor !is SimpleFunctionDescriptor) {
return false

View File

@@ -154,9 +154,12 @@ class InlineAnalyzerExtension(
}
private fun checkHasInlinableAndNullability(functionDescriptor: FunctionDescriptor, function: KtFunction, trace: BindingTrace) {
for ((parameter, descriptor) in function.valueParameters.zip(functionDescriptor.valueParameters)) {
if (checkInlinableParameter(descriptor, parameter, functionDescriptor, trace)) return
var hasInlineArgs = false
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
@@ -171,7 +174,7 @@ class InlineAnalyzerExtension(
expression: KtElement,
functionDescriptor: CallableDescriptor,
trace: BindingTrace?): Boolean {
if (InlineUtil.isInlineLambdaParameter(parameter)) {
if (InlineUtil.isInlineParameterExceptNullability(parameter)) {
if (parameter.type.isMarkedNullable) {
trace?.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor))
}

View File

@@ -32,12 +32,18 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch;
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
public class InlineUtil {
public static boolean isInlineLambdaParameter(@NotNull ParameterDescriptor valueParameterOrReceiver) {
public static boolean isInlineParameterExceptNullability(@NotNull ParameterDescriptor valueParameterOrReceiver) {
return !(valueParameterOrReceiver instanceof ValueParameterDescriptor
&& ((ValueParameterDescriptor) valueParameterOrReceiver).isNoinline()) &&
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) {
return descriptor instanceof FunctionDescriptor && getInlineStrategy((FunctionDescriptor) descriptor).isInline();
}
@@ -152,7 +158,7 @@ public class InlineUtil {
if (!(mapping instanceof ArgumentMatch)) return null;
ValueParameterDescriptor parameter = ((ArgumentMatch) mapping).getValueParameter();
return isInlineLambdaParameter(parameter) ? parameter : null;
return isInlineParameter(parameter) ? parameter : null;
}
public static boolean canBeInlineArgument(@Nullable PsiElement functionalExpression) {

View File

@@ -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
}

View File

@@ -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"
}

View File

@@ -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
}

View File

@@ -0,0 +1,4 @@
inline fun test(s: () -> Unit, <!NULLABLE_INLINE_PARAMETER!>p: (() -> Unit)?<!>) {
s()
p?.invoke()
}

View File

@@ -0,0 +1,3 @@
package
public inline fun test(/*0*/ s: () -> kotlin.Unit, /*1*/ p: (() -> kotlin.Unit)?): kotlin.Unit

View File

@@ -1339,6 +1339,24 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
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")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");

View File

@@ -1339,6 +1339,24 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
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")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");

View File

@@ -11263,6 +11263,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
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")
public void testKt4869() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/inline/kt4869.kt");

View File

@@ -1339,6 +1339,24 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
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")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");

View File

@@ -1339,6 +1339,24 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
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")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");

View File

@@ -416,6 +416,24 @@ public class InlineDefaultValuesTestsGenerated extends AbstractInlineDefaultValu
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")
public void testSimple() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxInline/defaultValues/maskElimination/simple.kt");

View File

@@ -79,7 +79,7 @@ public final class CallExpressionTranslator extends AbstractCallExpressionTransl
if (descriptor instanceof ValueParameterDescriptor) {
return InlineUtil.isInline(descriptor.getContainingDeclaration()) &&
InlineUtil.isInlineLambdaParameter((ParameterDescriptor) descriptor) &&
InlineUtil.isInlineParameter((ParameterDescriptor) descriptor) &&
!((ValueParameterDescriptor) descriptor).isCrossinline();
}