Extract logic to get function parameters for default value generation

For some reason, this logic was a bit different in JVM (FunctionCodegen)
and JS (FunctionBodyTranslator). For example, in JS the
EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND diagnostic was
reported even in the case when no expected function was found for the
actual function at all, which made it quite difficult to write
multiplatform sources for JS stdlib where it both should be compiled as
a part of the multiplatform project, and by itself (suppressing
NO_ACTUAL_FOR_EXPECT): in the latter case, the new error must have been
suppressed everywhere as well

 #KT-21913
This commit is contained in:
Alexander Udalov
2018-02-07 17:47:54 +01:00
parent 97314d010d
commit 80a7f92309
3 changed files with 36 additions and 46 deletions
@@ -20,11 +20,14 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.backend.common.bridges.findInterfaceImplementation
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.hasExpectModifier
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
@@ -175,4 +178,29 @@ object CodegenUtil {
}
return compatibleExpectedFunctions.firstOrNull() as FunctionDescriptor?
}
@JvmStatic
fun getFunctionParametersForDefaultValueGeneration(
descriptor: FunctionDescriptor,
trace: DiagnosticSink?
): List<ValueParameterDescriptor> {
if (descriptor.isActual) {
val expected = CodegenUtil.findExpectedFunctionForActual(descriptor)
if (expected != null && expected.valueParameters.any(ValueParameterDescriptor::declaresDefaultValue)) {
val element = DescriptorToSourceUtils.descriptorToDeclaration(expected)
if (element == null) {
if (trace != null) {
val actualDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(descriptor)
?: error("Not a source declaration: $descriptor")
trace.report(Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND.on(actualDeclaration))
}
return descriptor.valueParameters
}
return expected.valueParameters
}
}
return descriptor.valueParameters
}
}
@@ -74,7 +74,6 @@ import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DEC
import static org.jetbrains.kotlin.descriptors.ModalityKt.isOverridable;
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*;
import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUtilKt.isEffectivelyInlineOnly;
import static org.jetbrains.kotlin.diagnostics.Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND;
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE;
@@ -1110,16 +1109,9 @@ public class FunctionCodegen {
GenerationState state = parentCodegen.state;
JvmMethodSignature signature = state.getTypeMapper().mapSignatureWithGeneric(functionDescriptor, methodContext.getContextKind());
List<ValueParameterDescriptor> originalParameters = functionDescriptor.getValueParameters();
List<ValueParameterDescriptor> valueParameters;
if (functionDescriptor.isActual() && CollectionsKt.none(originalParameters, ValueParameterDescriptor::declaresDefaultValue)) {
FunctionDescriptor expected = CodegenUtil.findExpectedFunctionForActual(functionDescriptor);
assert expected != null : "Expected function should have been found earlier for " + functionDescriptor;
valueParameters = expected.getValueParameters();
}
else {
valueParameters = originalParameters;
}
// 'null' because the "could not find expected declaration" error has been already reported in isDefaultNeeded earlier
List<ValueParameterDescriptor> valueParameters =
CodegenUtil.getFunctionParametersForDefaultValueGeneration(functionDescriptor, null);
boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor);
FrameMap frameMap = createFrameMap(state, signature, functionDescriptor.getExtensionReceiverParameter(), valueParameters, isStatic);
@@ -1260,22 +1252,9 @@ public class FunctionCodegen {
}
private boolean isDefaultNeeded(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) {
if (descriptor.isActual()) {
FunctionDescriptor expected = CodegenUtil.findExpectedFunctionForActual(descriptor);
if (expected != null && CollectionsKt.any(expected.getValueParameters(), ValueParameterDescriptor::declaresDefaultValue)) {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(expected);
if (element == null) {
if (function != null) {
state.getDiagnostics().report(EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND.on(function));
}
return false;
}
return true;
}
}
return CollectionsKt.any(descriptor.getValueParameters(), ValueParameterDescriptor::declaresDefaultValue);
List<ValueParameterDescriptor> parameters =
CodegenUtil.getFunctionParametersForDefaultValueGeneration(descriptor, state.getDiagnostics());
return CollectionsKt.any(parameters, ValueParameterDescriptor::declaresDefaultValue);
}
private void generateBridge(
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.js.translate.utils;
import com.intellij.psi.PsiElement;
import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.backend.common.CodegenUtil;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
@@ -25,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.js.backend.ast.*;
import org.jetbrains.kotlin.js.backend.ast.metadata.MetadataProperties;
import org.jetbrains.kotlin.js.naming.NameSuggestion;
@@ -38,7 +36,6 @@ import org.jetbrains.kotlin.js.translate.reference.ReferenceTranslator;
import org.jetbrains.kotlin.psi.KtBlockExpression;
import org.jetbrains.kotlin.psi.KtDeclarationWithBody;
import org.jetbrains.kotlin.psi.KtExpression;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
import org.jetbrains.kotlin.resolve.source.KotlinSourceElementKt;
import org.jetbrains.kotlin.types.KotlinType;
@@ -83,22 +80,8 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
@NotNull TranslationContext context
) {
List<ValueParameterDescriptor> valueParameters = descriptor.getValueParameters();
List<ValueParameterDescriptor> valueParametersForDefaultValue;
if (descriptor.isActual() && CollectionsKt.none(valueParameters, ValueParameterDescriptor::declaresDefaultValue)) {
FunctionDescriptor expected = CodegenUtil.findExpectedFunctionForActual(descriptor);
if (expected != null) {
valueParametersForDefaultValue = expected.getValueParameters();
}
else {
PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(descriptor);
assert element != null : "No element found for descriptor: " + descriptor;
context.bindingTrace().report(Errors.EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND.on(element));
valueParametersForDefaultValue = valueParameters;
}
}
else {
valueParametersForDefaultValue = valueParameters;
}
List<ValueParameterDescriptor> valueParametersForDefaultValue =
CodegenUtil.getFunctionParametersForDefaultValueGeneration(descriptor, context.bindingTrace());
List<JsStatement> result = new ArrayList<>(valueParameters.size());
for (int i = 0; i < valueParameters.size(); i++) {