From 858731cac8a617617def1efa302062311dc27d42 Mon Sep 17 00:00:00 2001 From: Juan Chen Date: Tue, 12 May 2020 17:53:16 -0700 Subject: [PATCH] [FIR] add support for varargs in delegated constructor calls Also add support for spread operators as named arguments. --- .../kotlin/fir/backend/Fir2IrVisitor.kt | 4 +- ...rCallCompletionResultsWriterTransformer.kt | 57 ++++++++++--------- .../objectExtendsClassVararg.kt | 1 - .../codegen/box/mixedNamedPosition/varargs.kt | 1 - .../box/privateConstructors/withVarargs.kt | 1 - .../box/secondaryConstructors/varargs.kt | 1 - .../doNotCopyImmediatelyCreatedArrays.kt | 1 - .../codegen/box/vararg/varargInFunParam.kt | 1 - 8 files changed, 33 insertions(+), 34 deletions(-) diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index c59feb29c11..bf0dcf40726 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -258,7 +258,9 @@ class Fir2IrVisitor( varargArgumentsExpression.varargElementType.toIrType(), varargArgumentsExpression.arguments.map { arg -> convertToIrExpression(arg).run { - if (arg is FirSpreadArgumentExpression) IrSpreadElementImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this) + if (arg is FirSpreadArgumentExpression || arg is FirNamedArgumentExpression && arg.isSpread) { + IrSpreadElementImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, this) + } else this } }) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt index 520a10769da..332e9d9a482 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirCallCompletionResultsWriterTransformer.kt @@ -133,34 +133,8 @@ class FirCallCompletionResultsWriterTransformer( } else -> { resultType = typeRef.substituteTypeRef(subCandidate) - val argumentMapping = subCandidate.argumentMapping - val varargParameter = argumentMapping?.values?.firstOrNull { it.isVararg } result.argumentList.transformArguments(this, subCandidate.createArgumentsMapping()) - with(result.argumentList) call@{ - if (varargParameter != null) { - // Create a FirVarargArgumentExpression for the vararg arguments - val varargParameterTypeRef = varargParameter.returnTypeRef - val resolvedArrayType = varargParameterTypeRef.substitute(subCandidate) - val resolvedElementType = resolvedArrayType.arrayElementType(session) - var firstIndex = this@call.arguments.size - val newArgumentMapping = mutableMapOf() - val varargArgument = buildVarargArgumentsExpression { - varargElementType = varargParameterTypeRef.withReplacedConeType(resolvedElementType) - this.typeRef = varargParameterTypeRef.withReplacedConeType(resolvedArrayType) - for ((i, arg) in this@call.arguments.withIndex()) { - val valueParameter = argumentMapping[arg] ?: continue - if (valueParameter.isVararg) { - firstIndex = min(firstIndex, i) - arguments += arg - } else { - newArgumentMapping[arg] = valueParameter - } - } - } - newArgumentMapping[varargArgument] = varargParameter - subCandidate.argumentMapping = newArgumentMapping - } - } + subCandidate.handleVarargs(result.argumentList) subCandidate.argumentMapping?.let { result.replaceArgumentList(buildResolvedArgumentList(it)) } @@ -180,6 +154,34 @@ class FirCallCompletionResultsWriterTransformer( return result.compose() } + private fun Candidate.handleVarargs(argumentList: FirArgumentList) { + val argumentMapping = this.argumentMapping + val varargParameter = argumentMapping?.values?.firstOrNull { it.isVararg } + if (varargParameter != null) { + // Create a FirVarargArgumentExpression for the vararg arguments + val varargParameterTypeRef = varargParameter.returnTypeRef + val resolvedArrayType = varargParameterTypeRef.substitute(this) + val resolvedElementType = resolvedArrayType.arrayElementType(session) + var firstIndex = argumentList.arguments.size + val newArgumentMapping = mutableMapOf() + val varargArgument = buildVarargArgumentsExpression { + varargElementType = varargParameterTypeRef.withReplacedConeType(resolvedElementType) + this.typeRef = varargParameterTypeRef.withReplacedConeType(resolvedArrayType) + for ((i, arg) in argumentList.arguments.withIndex()) { + val valueParameter = argumentMapping[arg] ?: continue + if (valueParameter.isVararg) { + firstIndex = min(firstIndex, i) + arguments += arg + } else { + newArgumentMapping[arg] = valueParameter + } + } + } + newArgumentMapping[varargArgument] = varargParameter + this.argumentMapping = newArgumentMapping + } + } + private fun D.replaceTypeRefWithSubstituted( calleeReference: FirNamedReferenceWithCandidate, typeRef: FirResolvedTypeRef, @@ -291,6 +293,7 @@ class FirCallCompletionResultsWriterTransformer( val subCandidate = calleeReference.candidate delegatedConstructorCall.argumentList.transformArguments(this, calleeReference.candidate.createArgumentsMapping()) + subCandidate.handleVarargs(delegatedConstructorCall.argumentList) subCandidate.argumentMapping?.let { delegatedConstructorCall.replaceArgumentList(buildResolvedArgumentList(it)) } diff --git a/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsClassVararg.kt b/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsClassVararg.kt index 7e7f1e6c619..b0bb4aed5d1 100644 --- a/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsClassVararg.kt +++ b/compiler/testData/codegen/box/innerNested/superConstructorCall/objectExtendsClassVararg.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR open class SomeClass(val some: Double, val other: Int, vararg val args: String) { fun result() = args[1] } diff --git a/compiler/testData/codegen/box/mixedNamedPosition/varargs.kt b/compiler/testData/codegen/box/mixedNamedPosition/varargs.kt index 2d8e525052e..b2f5196341d 100644 --- a/compiler/testData/codegen/box/mixedNamedPosition/varargs.kt +++ b/compiler/testData/codegen/box/mixedNamedPosition/varargs.kt @@ -1,5 +1,4 @@ // !LANGUAGE: +NewInference +MixedNamedArgumentsInTheirOwnPosition -// IGNORE_BACKEND_FIR: JVM_IR fun foo1( vararg p1: Int, diff --git a/compiler/testData/codegen/box/privateConstructors/withVarargs.kt b/compiler/testData/codegen/box/privateConstructors/withVarargs.kt index e45123600f8..f7791f1968c 100644 --- a/compiler/testData/codegen/box/privateConstructors/withVarargs.kt +++ b/compiler/testData/codegen/box/privateConstructors/withVarargs.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // See also KT-6299 public open class Outer private constructor(val s: String, vararg i: Int) { class Inner: Outer("xyz") diff --git a/compiler/testData/codegen/box/secondaryConstructors/varargs.kt b/compiler/testData/codegen/box/secondaryConstructors/varargs.kt index 19b22b853a7..39bfb8bf7a9 100644 --- a/compiler/testData/codegen/box/secondaryConstructors/varargs.kt +++ b/compiler/testData/codegen/box/secondaryConstructors/varargs.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun join(x: Array): String { var result = "" for (i in x) { diff --git a/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt b/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt index 616f94db2ab..6cc4d47dc23 100644 --- a/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt +++ b/compiler/testData/codegen/box/vararg/doNotCopyImmediatelyCreatedArrays.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun booleanVararg(vararg xs: Boolean) { if (xs.size != 1 && xs[0] != true) throw AssertionError() } diff --git a/compiler/testData/codegen/box/vararg/varargInFunParam.kt b/compiler/testData/codegen/box/vararg/varargInFunParam.kt index 44f18b59d49..6f0d02a20d0 100644 --- a/compiler/testData/codegen/box/vararg/varargInFunParam.kt +++ b/compiler/testData/codegen/box/vararg/varargInFunParam.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR fun box(): String { if (test1() != "") return "fail 1" if (test1(1) != "1") return "fail 2"