Add diagnostics for default lambda inlining

This commit is contained in:
Mikhael Bogdanov
2017-05-15 16:52:15 +02:00
parent 81c2e1dd8c
commit 0ac23c789e
15 changed files with 282 additions and 14 deletions
@@ -926,7 +926,7 @@ public interface Errors {
DiagnosticFactory0<KtDeclaration> INLINE_PROPERTY_WITH_BACKING_FIELD = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<KtAnnotationEntry> NON_INTERNAL_PUBLISHED_API = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, CallableDescriptor> PROTECTED_CALL_FROM_PUBLIC_INLINE = DiagnosticFactory1.create(WARNING);
DiagnosticFactory2<KtElement, KtExpression, DeclarationDescriptor> INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE = DiagnosticFactory2.create(ERROR);
DiagnosticFactory0<PsiElement> NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, CallableDescriptor> ILLEGAL_SUSPEND_FUNCTION_CALL = DiagnosticFactory1.create(ERROR);
@@ -836,6 +836,7 @@ public class DefaultErrorMessages {
MAP.put(INLINE_PROPERTY_WITH_BACKING_FIELD, "Inline property cannot have backing field");
MAP.put(NON_INTERNAL_PUBLISHED_API, "@PublishedApi annotation is only applicable for internal declaration");
MAP.put(PROTECTED_CALL_FROM_PUBLIC_INLINE, "Protected function call from public-API inline function is deprecated", NAME);
MAP.put(INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE, "Invalid default value for inline parameter: ''{0}''. Only lambdas, anonymous functions, and callable references are supported", ELEMENT_TEXT, SHORT_NAMES_IN_TYPES);
//Inline non locals
MAP.put(NON_LOCAL_RETURN_NOT_ALLOWED, "Can''t inline ''{0}'' here: it may contain non-local returns. Add ''crossinline'' modifier to parameter declaration ''{0}''", ELEMENT_TEXT);
MAP.put(INLINE_CALL_CYCLE, "The ''{0}'' invocation is a part of inline cycle", NAME);
@@ -17,6 +17,7 @@
package org.jetbrains.kotlin.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.config.LanguageVersionSettings;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.psi.KtCallableDeclaration;
import org.jetbrains.kotlin.psi.KtNamedFunction;
@@ -37,10 +38,16 @@ public class AnalyzerExtensions {
@NotNull private final BindingTrace trace;
@NotNull private final Iterable<ReasonableInlineRule> reasonableInlineRules;
private LanguageVersionSettings languageVersionSettings;
public AnalyzerExtensions(@NotNull BindingTrace trace, @NotNull Iterable<ReasonableInlineRule> reasonableInlineRules) {
public AnalyzerExtensions(
@NotNull BindingTrace trace,
@NotNull Iterable<ReasonableInlineRule> reasonableInlineRules,
@NotNull LanguageVersionSettings languageVersionSettings
) {
this.trace = trace;
this.reasonableInlineRules = reasonableInlineRules;
this.languageVersionSettings = languageVersionSettings;
}
public void process(@NotNull BodiesResolveContext bodiesResolveContext) {
@@ -66,7 +73,7 @@ public class AnalyzerExtensions {
@NotNull
private List<InlineAnalyzerExtension> getFunctionExtensions(@NotNull FunctionDescriptor functionDescriptor) {
if (InlineUtil.isInline(functionDescriptor)) {
return Collections.singletonList(new InlineAnalyzerExtension(reasonableInlineRules));
return Collections.singletonList(new InlineAnalyzerExtension(reasonableInlineRules, languageVersionSettings));
}
return Collections.emptyList();
}
@@ -74,7 +81,7 @@ public class AnalyzerExtensions {
@NotNull
private List<InlineAnalyzerExtension> getPropertyExtensions(@NotNull PropertyDescriptor propertyDescriptor) {
if (InlineUtil.hasInlineAccessors(propertyDescriptor)) {
return Collections.singletonList(new InlineAnalyzerExtension(reasonableInlineRules));
return Collections.singletonList(new InlineAnalyzerExtension(reasonableInlineRules, languageVersionSettings));
}
return Collections.emptyList();
}
@@ -16,6 +16,8 @@
package org.jetbrains.kotlin.resolve.inline
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.isInlineOnlyOrReifiable
import org.jetbrains.kotlin.diagnostics.Errors
@@ -26,7 +28,10 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingTrace
import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue
class InlineAnalyzerExtension(private val reasonableInlineRules: Iterable<ReasonableInlineRule>) : AnalyzerExtensions.AnalyzerExtension {
class InlineAnalyzerExtension(
private val reasonableInlineRules: Iterable<ReasonableInlineRule>,
private val languageVersionSettings: LanguageVersionSettings
) : AnalyzerExtensions.AnalyzerExtension {
override fun process(descriptor: CallableMemberDescriptor, functionOrProperty: KtCallableDeclaration, trace: BindingTrace) {
checkModalityAndOverrides(descriptor, functionOrProperty, trace)
@@ -86,14 +91,28 @@ class InlineAnalyzerExtension(private val reasonableInlineRules: Iterable<Reason
for (parameter in functionDescriptor.valueParameters) {
if (parameter.hasDefaultValue()) {
val ktParameter = ktParameters[parameter.index]
//report unsupported default only on inlinable lambda and on parameter with inherited default (there is some problems to inline it)
if (checkInlinableParameter(parameter, ktParameter, functionDescriptor, null) || !parameter.declaresDefaultValue()) {
trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(ktParameter, ktParameter, functionDescriptor))
//Always report unsupported error on functional parameter with inherited default (there are some problems with inlining)
val inheritDefaultValues = !parameter.declaresDefaultValue()
if (checkInlinableParameter(parameter, ktParameter, functionDescriptor, null) || inheritDefaultValues) {
if (inheritDefaultValues || !languageVersionSettings.supportsFeature(LanguageFeature.InlineDefaultFunctionalParameters)) {
trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(ktParameter, ktParameter, functionDescriptor))
}
else {
checkDefaultValue(trace, parameter, ktParameter)
}
}
}
}
}
private fun checkDefaultValue(trace: BindingTrace, parameterDescriptor: ValueParameterDescriptor, ktParameter: KtParameter) {
ktParameter.defaultValue?.let { defaultValue ->
if (!InlineUtil.isInlinableParameterExpression(KtPsiUtil.deparenthesize(defaultValue))) {
trace.report(Errors.INVALID_DEFAULT_FUNCTIONAL_PARAMETER_FOR_INLINE.on(defaultValue, defaultValue, parameterDescriptor))
}
}
}
private fun checkModalityAndOverrides(
callableDescriptor: CallableMemberDescriptor,
functionOrProperty: KtCallableDeclaration,
@@ -200,4 +200,10 @@ public class InlineUtil {
return false;
}
public static boolean isInlinableParameterExpression(@Nullable KtExpression deparenthesized) {
return deparenthesized instanceof KtLambdaExpression ||
deparenthesized instanceof KtNamedFunction ||
deparenthesized instanceof KtCallableReferenceExpression;
}
}