From 4079735bf203891fd0734d004c1add8cca98321a Mon Sep 17 00:00:00 2001 From: Mikhael Bogdanov Date: Thu, 21 Nov 2013 16:38:35 +0400 Subject: [PATCH] Diagnostic for nullable parameter of Function type --- .../calls/InlineCallResolverExtension.java | 26 +++++------ .../extension/InlineAnalyzerExtension.java | 44 +++++++++++++------ .../tests/inline/nullableFunction.kt | 21 +++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 +++ 4 files changed, 69 insertions(+), 27 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inline/nullableFunction.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java index 673be10562e..3c649d60911 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java @@ -37,9 +37,9 @@ import java.util.*; public class InlineCallResolverExtension implements CallResolverExtension { - private SimpleFunctionDescriptor descriptor; + private final SimpleFunctionDescriptor descriptor; - private Set inlinableParameters = new HashSet(); + private final Set inlinableParameters = new HashSet(); private final boolean isEffectivelyPublicApiFunction; @@ -48,21 +48,16 @@ public class InlineCallResolverExtension implements CallResolverExtension { this.descriptor = descriptor; this.isEffectivelyPublicApiFunction = isEffectivelyPublicApi(descriptor); - Iterator iterator = descriptor.getValueParameters().iterator(); - while (iterator.hasNext()) { - ValueParameterDescriptor next = iterator.next(); - JetType type = next.getType(); - if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type)) { - if (!InlineUtil.hasNoinlineAnnotation(next)) { - inlinableParameters.add(next); - } + for (ValueParameterDescriptor param : descriptor.getValueParameters()) { + if (isInlinableParameter(param)) { + inlinableParameters.add(param); } } //add extension receiver as inlineable ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); if (receiverParameter != null) { - if (isExactFunctionOrExtensionFunctionType(receiverParameter.getType())) { + if (isInlinableParameter(receiverParameter)) { inlinableParameters.add(receiverParameter); } } @@ -178,9 +173,12 @@ public class InlineCallResolverExtension implements CallResolverExtension { } } - - private boolean isExactFunctionOrExtensionFunctionType(@NotNull JetType type) { - return KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type); + private boolean isInlinableParameter(@NotNull CallableDescriptor descriptor) { + JetType type = descriptor.getReturnType(); + return type != null && + KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type) && + !type.isNullable() && + !InlineUtil.hasNoinlineAnnotation(descriptor); } private static boolean isInvokeOrInlineExtension(@NotNull CallableDescriptor descriptor) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java index 93f67e61090..02710e3d0c1 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java @@ -22,6 +22,7 @@ import org.jetbrains.jet.lang.diagnostics.Errors; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.FunctionAnalyzerExtension; +import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.InlineUtil; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; @@ -44,7 +45,7 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz checkDefaults(descriptor, function, trace); checkModality(descriptor, function, trace); - checkHashInlinable(descriptor, function, trace); + checkHashInlinableAndNullability(descriptor, function, trace); JetVisitorVoid visitor = new JetVisitorVoid() { @@ -106,28 +107,45 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz trace.report(Errors.DECLARATION_CANT_BE_INLINED.on(function)); } - private void checkHashInlinable( + private void checkHashInlinableAndNullability( @NotNull FunctionDescriptor functionDescriptor, @NotNull JetFunction function, @NotNull BindingTrace trace ) { + boolean hasInlinable = false; List parameters = functionDescriptor.getValueParameters(); + int index = 0; for (ValueParameterDescriptor parameter : parameters) { - KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); - if (builtIns.isExactFunctionOrExtensionFunctionType(parameter.getType())) { - if (!InlineUtil.hasNoinlineAnnotation(parameter)) { - return; - } - } + hasInlinable |= checkParameter(parameter, function.getValueParameters().get(index++), functionDescriptor, trace); } ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); if (receiverParameter != null) { - if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(receiverParameter.getType())) { - //or extension on inlinable function - return; - } + JetTypeReference receiver = function.getReceiverTypeRef(); + hasInlinable |= checkParameter(receiverParameter, receiver, functionDescriptor, trace); } - trace.report(Errors.NOTHING_TO_INLINE.on(function, functionDescriptor)); + if (!hasInlinable) { + trace.report(Errors.NOTHING_TO_INLINE.on(function, functionDescriptor)); + } + } + + private static boolean checkParameter( + @NotNull CallableDescriptor parameter, + @NotNull JetElement expression, + @NotNull FunctionDescriptor functionDescriptor, + @NotNull BindingTrace trace + ) { + KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); + JetType type = parameter.getReturnType(); + if (type != null && builtIns.isExactFunctionOrExtensionFunctionType(type)) { + if (!InlineUtil.hasNoinlineAnnotation(parameter)) { + if (type.isNullable()) { + trace.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor)); + } else { + return true; + } + } + } + return false; } } diff --git a/compiler/testData/diagnostics/tests/inline/nullableFunction.kt b/compiler/testData/diagnostics/tests/inline/nullableFunction.kt new file mode 100644 index 00000000000..7beb39cbb72 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/nullableFunction.kt @@ -0,0 +1,21 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +public inline fun Function1?.submit(action: ()->T) { + this?.invoke(11) +} + +public inline fun submit(action: Function1?, s: () -> Int) { + action?.invoke(10) +} + +public inline fun submitNoInline(noinline action: Function1?, s: () -> Int) { + action?.invoke(10) +} + +public inline fun Function1?.submit() { + +} + +public inline fun submit(action: Function1?) { + +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index 86f54331042..cc7d073627c 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -3792,6 +3792,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage doTest("compiler/testData/diagnostics/tests/inline/nothingToInline.kt"); } + @TestMetadata("nullableFunction.kt") + public void testNullableFunction() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/nullableFunction.kt"); + } + @TestMetadata("propagation.kt") public void testPropagation() throws Exception { doTest("compiler/testData/diagnostics/tests/inline/propagation.kt");