Support default arguments for expected declarations

#KT-21913 Fixed
This commit is contained in:
Alexander Udalov
2018-01-12 20:50:24 +01:00
parent d356f52873
commit db4ce703a6
36 changed files with 794 additions and 77 deletions
@@ -13732,6 +13732,54 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
}
}
@TestMetadata("compiler/testData/codegen/box/multiplatform")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Multiplatform extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInMultiplatform() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/multiplatform"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DefaultArguments extends AbstractJsCodegenBoxTest {
public void testAllFilesPresentInDefaultArguments() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/multiplatform/defaultArguments"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments/constructor.kt");
doTest(fileName);
}
@TestMetadata("function.kt")
public void testFunction() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments/function.kt");
doTest(fileName);
}
@TestMetadata("inheritedFromCommonClass.kt")
public void testInheritedFromCommonClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromCommonClass.kt");
doTest(fileName);
}
@TestMetadata("inheritedFromExpectedClass.kt")
public void testInheritedFromExpectedClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments/inheritedFromExpectedClass.kt");
doTest(fileName);
}
@TestMetadata("inlineFunctionWithDefaultLambda.kt")
public void testInlineFunctionWithDefaultLambda() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/multiplatform/defaultArguments/inlineFunctionWithDefaultLambda.kt");
doTest(fileName);
}
}
}
@TestMetadata("compiler/testData/codegen/box/nonLocalReturns")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -17,12 +17,15 @@
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;
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;
@@ -35,6 +38,7 @@ 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;
@@ -74,18 +78,36 @@ public final class FunctionBodyTranslator extends AbstractTranslator {
}
@NotNull
public static List<JsStatement> setDefaultValueForArguments(@NotNull FunctionDescriptor descriptor,
@NotNull TranslationContext functionBodyContext) {
List<ValueParameterDescriptor> valueParameters = descriptor.getValueParameters();
public static List<JsStatement> setDefaultValueForArguments(
@NotNull FunctionDescriptor descriptor,
@NotNull TranslationContext context
) {
List<ValueParameterDescriptor> originalParameters = descriptor.getValueParameters();
List<ValueParameterDescriptor> valueParameters;
if (descriptor.isActual() && CollectionsKt.none(originalParameters, ValueParameterDescriptor::declaresDefaultValue)) {
FunctionDescriptor expected = CodegenUtil.findExpectedFunctionForActual(descriptor);
if (expected != null) {
valueParameters = 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));
valueParameters = originalParameters;
}
}
else {
valueParameters = originalParameters;
}
List<JsStatement> result = new ArrayList<>(valueParameters.size());
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!valueParameter.declaresDefaultValue()) continue;
JsExpression jsNameRef = ReferenceTranslator.translateAsValueReference(valueParameter, functionBodyContext);
JsExpression jsNameRef = ReferenceTranslator.translateAsValueReference(valueParameter, context);
KtExpression defaultArgument = BindingUtils.getDefaultArgument(valueParameter);
JsBlock defaultArgBlock = new JsBlock();
JsExpression defaultValue = Translation.translateAsExpression(defaultArgument, functionBodyContext, defaultArgBlock);
JsExpression defaultValue = Translation.translateAsExpression(defaultArgument, context, defaultArgBlock);
PsiElement psi = KotlinSourceElementKt.getPsi(valueParameter.getSource());
JsStatement assignStatement = assignment(jsNameRef, defaultValue).source(psi).makeStmt();
JsStatement thenStatement = JsAstUtils.mergeStatementInBlockIfNeeded(assignStatement, defaultArgBlock);