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 { 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; private final boolean isEffectivelyPublicApiFunction;
@@ -48,21 +48,16 @@ public class InlineCallResolverExtension implements CallResolverExtension {
this.descriptor = descriptor; this.descriptor = descriptor;
this.isEffectivelyPublicApiFunction = isEffectivelyPublicApi(descriptor); this.isEffectivelyPublicApiFunction = isEffectivelyPublicApi(descriptor);
Iterator<ValueParameterDescriptor> iterator = descriptor.getValueParameters().iterator(); for (ValueParameterDescriptor param : descriptor.getValueParameters()) {
while (iterator.hasNext()) { if (isInlinableParameter(param)) {
ValueParameterDescriptor next = iterator.next(); inlinableParameters.add(param);
JetType type = next.getType();
if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type)) {
if (!InlineUtil.hasNoinlineAnnotation(next)) {
inlinableParameters.add(next);
}
} }
} }
//add extension receiver as inlineable //add extension receiver as inlineable
ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
if (receiverParameter != null) { if (receiverParameter != null) {
if (isExactFunctionOrExtensionFunctionType(receiverParameter.getType())) { if (isInlinableParameter(receiverParameter)) {
inlinableParameters.add(receiverParameter); inlinableParameters.add(receiverParameter);
} }
} }
@@ -178,9 +173,12 @@ public class InlineCallResolverExtension implements CallResolverExtension {
} }
} }
private boolean isInlinableParameter(@NotNull CallableDescriptor descriptor) {
private boolean isExactFunctionOrExtensionFunctionType(@NotNull JetType type) { JetType type = descriptor.getReturnType();
return KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type); return type != null &&
KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type) &&
!type.isNullable() &&
!InlineUtil.hasNoinlineAnnotation(descriptor);
} }
private static boolean isInvokeOrInlineExtension(@NotNull CallableDescriptor 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.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.FunctionAnalyzerExtension; 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.InlineUtil;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
@@ -44,7 +45,7 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz
checkDefaults(descriptor, function, trace); checkDefaults(descriptor, function, trace);
checkModality(descriptor, function, trace); checkModality(descriptor, function, trace);
checkHashInlinable(descriptor, function, trace); checkHashInlinableAndNullability(descriptor, function, trace);
JetVisitorVoid visitor = new JetVisitorVoid() { JetVisitorVoid visitor = new JetVisitorVoid() {
@@ -106,28 +107,45 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz
trace.report(Errors.DECLARATION_CANT_BE_INLINED.on(function)); trace.report(Errors.DECLARATION_CANT_BE_INLINED.on(function));
} }
private void checkHashInlinable( private void checkHashInlinableAndNullability(
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
@NotNull JetFunction function, @NotNull JetFunction function,
@NotNull BindingTrace trace @NotNull BindingTrace trace
) { ) {
boolean hasInlinable = false;
List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters(); List<ValueParameterDescriptor> parameters = functionDescriptor.getValueParameters();
int index = 0;
for (ValueParameterDescriptor parameter : parameters) { for (ValueParameterDescriptor parameter : parameters) {
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); hasInlinable |= checkParameter(parameter, function.getValueParameters().get(index++), functionDescriptor, trace);
if (builtIns.isExactFunctionOrExtensionFunctionType(parameter.getType())) {
if (!InlineUtil.hasNoinlineAnnotation(parameter)) {
return;
}
}
} }
ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter();
if (receiverParameter != null) { if (receiverParameter != null) {
if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(receiverParameter.getType())) { JetTypeReference receiver = function.getReceiverTypeRef();
//or extension on inlinable function hasInlinable |= checkParameter(receiverParameter, receiver, functionDescriptor, trace);
return;
}
} }
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"); 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") @TestMetadata("propagation.kt")
public void testPropagation() throws Exception { public void testPropagation() throws Exception {
doTest("compiler/testData/diagnostics/tests/inline/propagation.kt"); doTest("compiler/testData/diagnostics/tests/inline/propagation.kt");