Diagnostic for nullable parameter of Function type

This commit is contained in:
Mikhael Bogdanov
2013-11-21 16:38:35 +04:00
parent 40239c42a7
commit 4079735bf2
4 changed files with 69 additions and 27 deletions
@@ -37,9 +37,9 @@ import java.util.*;
public class InlineCallResolverExtension implements CallResolverExtension {
private SimpleFunctionDescriptor descriptor;
private final SimpleFunctionDescriptor descriptor;
private Set<DeclarationDescriptor> inlinableParameters = new HashSet<DeclarationDescriptor>();
private final Set<CallableDescriptor> inlinableParameters = new HashSet<CallableDescriptor>();
private final boolean isEffectivelyPublicApiFunction;
@@ -48,21 +48,16 @@ public class InlineCallResolverExtension implements CallResolverExtension {
this.descriptor = descriptor;
this.isEffectivelyPublicApiFunction = isEffectivelyPublicApi(descriptor);
Iterator<ValueParameterDescriptor> 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) {
@@ -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<ValueParameterDescriptor> 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;
}
}
@@ -0,0 +1,21 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
public inline fun <T> <!NULLABLE_INLINE_PARAMETER!>Function1<Int, Int>?<!>.submit(action: ()->T) {
this?.invoke(11)
}
public inline fun <T> submit(<!NULLABLE_INLINE_PARAMETER!>action: Function1<Int, Int>?<!>, s: () -> Int) {
action?.invoke(10)
}
public inline fun <T> submitNoInline(noinline action: Function1<Int, Int>?, s: () -> Int) {
action?.invoke(10)
}
<!NOTHING_TO_INLINE!>public inline fun <T> <!NULLABLE_INLINE_PARAMETER!>Function1<Int, Int>?<!>.submit() {
}<!>
<!NOTHING_TO_INLINE!>public inline fun <T> submit(<!NULLABLE_INLINE_PARAMETER!>action: Function1<Int, Int>?<!>) {
}<!>
@@ -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");