FIR: introduce & resolve spread named arguments #KT-31575 Fixed

This commit is contained in:
Mikhail Glukhikh
2019-05-24 23:48:36 +03:00
parent 806d2d628c
commit 2db8409d85
18 changed files with 117 additions and 47 deletions
@@ -1212,8 +1212,16 @@ class HtmlFirDump internal constructor(private var linkResolver: FirLinkResolver
is FirNamedArgumentExpression -> {
simpleName(expression.name)
+" = "
if (expression.isSpread) {
+"*"
}
generate(expression.expression)
}
is FirSpreadArgumentExpression -> {
+"*"
generate(expression.expression)
}
is FirLambdaArgumentExpression -> {
keyword("lambda")
+" = "
@@ -288,7 +288,7 @@ class KotlinDeserializedJvmSymbolsProvider(
result += FirAnnotationCallImpl(session, null, null, symbol.toDefaultResolvedTypeRef(annotationClassId)).apply {
for ((name, expression) in argumentMap) {
arguments += FirNamedArgumentExpressionImpl(
this@KotlinDeserializedJvmSymbolsProvider.session, null, name, expression
this@KotlinDeserializedJvmSymbolsProvider.session, null, name, false, expression
)
}
}
@@ -199,7 +199,12 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) {
{ expression }.toFirExpression("Argument is absent")
}
}
return if (name != null) FirNamedArgumentExpressionImpl(session, expression, name, firExpression) else firExpression
val isSpread = getSpreadElement() != null
return when {
name != null -> FirNamedArgumentExpressionImpl(session, expression, name, isSpread, firExpression)
isSpread -> FirSpreadArgumentExpressionImpl(session, expression, firExpression)
else -> firExpression
}
}
private fun KtPropertyAccessor?.toFirPropertyAccessor(
@@ -83,7 +83,7 @@ abstract class AbstractAnnotationDeserializer(
val parameter = parameterByName[name] ?: return@mapNotNull null
val value = resolveValue(parameter.returnTypeRef, it.value, nameResolver) ?: return@mapNotNull null
FirNamedArgumentExpressionImpl(
session, null, name, value
session, null, name, false, value
)
}
}
@@ -54,18 +54,7 @@ fun resolveArgumentExpression(
is FirCallableReferenceAccess -> Unit
// TODO:!
//TODO: Collection literal
is FirLambdaArgumentExpression -> resolveArgumentExpression(
csBuilder,
argument.expression,
expectedType,
expectedTypeRef,
sink,
isReceiver,
isSafeCall,
acceptLambdaAtoms,
typeProvider
)
is FirNamedArgumentExpression -> resolveArgumentExpression(
is FirWrappedArgumentExpression -> resolveArgumentExpression(
csBuilder,
argument.expression,
expectedType,
@@ -180,7 +169,7 @@ internal fun FirExpression.getExpectedType(
// if (this.isSpread || this.isArrayAssignedAsNamedArgumentInAnnotation(parameter, languageVersionSettings)) {
// parameter.type.unwrap()
// } else {
if (parameter.isVararg) {
if (parameter.isVararg && (this !is FirWrappedArgumentExpression || !isSpread)) {
parameter.returnTypeRef.coneTypeUnsafe<ConeKotlinType>().varargElementType(session)
} else {
parameter.returnTypeRef.coneTypeUnsafe()
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.fir.resolve.calls
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
import org.jetbrains.kotlin.fir.expressions.FirExpression
@@ -13,8 +12,6 @@ import org.jetbrains.kotlin.fir.expressions.FirLambdaArgumentExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.types.ConeClassType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
class FirCallArgumentsProcessor(
private val function: FirFunction,
@@ -25,7 +22,7 @@ class FirCallArgumentsProcessor(
fun process(): Result {
var currentState: State = State.PositionalOnly(function.valueParameters)
for (argument in arguments) {
if (argument is FirWrappedArgumentExpression) {
if (argument is FirNamedArgumentExpression || argument is FirLambdaArgumentExpression) {
currentState = State.PositionalThenNamed(
function.valueParameters,
currentState.argumentMap,
@@ -65,21 +62,19 @@ class FirCallArgumentsProcessor(
val currentParameter get() = valueParameters.getOrNull(currentParameterIndex)
fun nextParameter() {
val currentParameter = currentParameter ?: return
if (currentParameter.isVararg) return
usedParameters += currentParameter
currentParameterIndex++
}
override fun processArgument(argument: FirExpression): MappingStatus {
require(argument !is FirNamedArgumentExpression) {
"Positional-only argument processor state should not receiver ${argument.render()}"
"Positional-only argument processor state should not receive ${argument.render()}"
}
val currentParameter = currentParameter ?: return MappingStatus.ERROR
argumentMap[argument] = currentParameter
nextParameter()
if (!currentParameter.isVararg ||
argument is FirWrappedArgumentExpression && argument.isSpread
) {
usedParameters += currentParameter
currentParameterIndex++
}
return MappingStatus.SUCCESS
}
@@ -1166,17 +1166,10 @@ private object ReplaceInArguments : FirTransformer<Map<FirElement, FirElement>>(
return (functionCall.transformChildren(this, data) as FirStatement).compose()
}
override fun transformNamedArgumentExpression(
namedArgumentExpression: FirNamedArgumentExpression,
override fun transformWrappedArgumentExpression(
wrappedArgumentExpression: FirWrappedArgumentExpression,
data: Map<FirElement, FirElement>
): CompositeTransformResult<FirStatement> {
return (namedArgumentExpression.transformChildren(this, data) as FirStatement).compose()
}
override fun transformLambdaArgumentExpression(
lambdaArgumentExpression: FirLambdaArgumentExpression,
data: Map<FirElement, FirElement>
): CompositeTransformResult<FirStatement> {
return (lambdaArgumentExpression.transformChildren(this, data) as FirStatement).compose()
return (wrappedArgumentExpression.transformChildren(this, data) as FirStatement).compose()
}
}
@@ -5,6 +5,7 @@ fun test() {
foo(1)
foo(1, "")
foo(1, "my", "yours")
foo(1, *arrayOf("my", "yours"))
foo("")
foo(1, 2)
+2 -1
View File
@@ -7,9 +7,10 @@ FILE: vararg.kt
R|/foo|(Int(1))
R|/foo|(Int(1), String())
R|/foo|(Int(1), String(my), String(yours))
R|/foo|(Int(1), *R|kotlin/arrayOf|<R|kotlin/String|>(String(my), String(yours)))
<Inapplicable(INAPPLICABLE): [/foo]>#(String())
<Inapplicable(INAPPLICABLE): [/foo]>#(Int(1), Int(2))
R|/bar|(Int(1), z = Boolean(true), y = R|kotlin/arrayOf|<R|TypeVariable(T)|>(String(my), String(yours)))
R|/bar|(Int(1), z = Boolean(true), y = *R|kotlin/arrayOf|<R|kotlin/String|>(String(my), String(yours)))
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(Int(0), z = Boolean(false), y = String(), y = String(other))
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(Int(0), String(), Boolean(true))
}
@@ -627,9 +627,19 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
override fun visitNamedArgumentExpression(namedArgumentExpression: FirNamedArgumentExpression) {
print(namedArgumentExpression.name)
print(" = ")
if (namedArgumentExpression.isSpread) {
print("*")
}
namedArgumentExpression.expression.accept(this)
}
override fun visitSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression) {
if (spreadArgumentExpression.isSpread) {
print("*")
}
spreadArgumentExpression.expression.accept(this)
}
override fun visitLambdaArgumentExpression(lambdaArgumentExpression: FirLambdaArgumentExpression) {
print("<L> = ")
lambdaArgumentExpression.expression.accept(this)
@@ -0,0 +1,16 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.expressions
import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirSpreadArgumentExpression : FirWrappedArgumentExpression {
override val isSpread: Boolean
get() = true
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R =
visitor.visitSpreadArgumentExpression(this, data)
}
@@ -11,6 +11,9 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitor
interface FirWrappedArgumentExpression : FirExpression {
val expression: FirExpression
val isSpread: Boolean
get() = false
override val typeRef: FirTypeRef
get() = expression.typeRef
@@ -9,7 +9,6 @@ import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirLambdaArgumentExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.transformSingle
import org.jetbrains.kotlin.fir.types.FirTypeRef
@@ -20,6 +19,7 @@ class FirNamedArgumentExpressionImpl(
session: FirSession,
psi: PsiElement?,
override val name: Name,
override val isSpread: Boolean,
override var expression: FirExpression
) : FirNamedArgumentExpression, FirAbstractExpression(session, psi) {
override var typeRef: FirTypeRef
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.expressions.impl
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.FirSpreadArgumentExpression
import org.jetbrains.kotlin.fir.transformSingle
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.FirTransformer
class FirSpreadArgumentExpressionImpl(
session: FirSession,
psi: PsiElement?,
override var expression: FirExpression
) : FirSpreadArgumentExpression, FirAbstractExpression(session, psi) {
override var typeRef: FirTypeRef
get() = super<FirSpreadArgumentExpression>.typeRef
set(_) {}
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirElement {
expression = expression.transformSingle(transformer, data)
return super<FirAbstractExpression>.transformChildren(transformer, data)
}
}
@@ -300,6 +300,10 @@ abstract class FirTransformer<in D> : FirVisitor<CompositeTransformResult<FirEle
return transformWrappedArgumentExpression(namedArgumentExpression, data)
}
open fun transformSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression, data: D): CompositeTransformResult<FirStatement> {
return transformWrappedArgumentExpression(spreadArgumentExpression, data)
}
open fun transformLoop(loop: FirLoop, data: D): CompositeTransformResult<FirStatement> {
return transformStatement(loop, data)
}
@@ -680,6 +684,10 @@ abstract class FirTransformer<in D> : FirVisitor<CompositeTransformResult<FirEle
return transformReturnExpression(returnExpression, data)
}
final override fun visitSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression, data: D): CompositeTransformResult<FirElement> {
return transformSpreadArgumentExpression(spreadArgumentExpression, data)
}
final override fun visitStarProjection(starProjection: FirStarProjection, data: D): CompositeTransformResult<FirElement> {
return transformStarProjection(starProjection, data)
}
@@ -300,6 +300,10 @@ abstract class FirVisitor<out R, in D> {
return visitWrappedArgumentExpression(namedArgumentExpression, data)
}
open fun visitSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression, data: D): R {
return visitWrappedArgumentExpression(spreadArgumentExpression, data)
}
open fun visitLoop(loop: FirLoop, data: D): R {
return visitStatement(loop, data)
}
@@ -300,6 +300,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitWrappedArgumentExpression(namedArgumentExpression, null)
}
open fun visitSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression) {
visitWrappedArgumentExpression(spreadArgumentExpression, null)
}
open fun visitLoop(loop: FirLoop) {
visitStatement(loop, null)
}
@@ -680,6 +684,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitReturnExpression(returnExpression)
}
final override fun visitSpreadArgumentExpression(spreadArgumentExpression: FirSpreadArgumentExpression, data: Nothing?) {
visitSpreadArgumentExpression(spreadArgumentExpression)
}
final override fun visitStarProjection(starProjection: FirStarProjection, data: Nothing?) {
visitStarProjection(starProjection)
}
+5 -6
View File
@@ -21,16 +21,15 @@ FILE fqName:<root> fileName:/vararg.kt
RETURN type=kotlin.Nothing from='public final fun <get-test2> (): kotlin.Array<kotlin.String> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test2 type:kotlin.Array<kotlin.String> visibility:public [final,static] ' type=kotlin.Array<kotlin.String> origin=null
PROPERTY name:test3 visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:test3 type:kotlin.Array<kotlin.String> visibility:public [final,static]
FIELD PROPERTY_BACKING_FIELD name:test3 type:IrErrorType visibility:public [final,static]
EXPRESSION_BODY
ERROR_CALL 'Cannot bind 4 arguments to arrayOf call with 1 parameters' type=kotlin.Array<kotlin.String>
ERROR_CALL 'Unresolved reference: <Inapplicable(PARAMETER_MAPPING_ERROR): [kotlin/arrayOf]>#' type=IrErrorType
CONST String type=kotlin.String value="0"
CALL 'public final fun <get-test2> (): kotlin.Array<kotlin.String> declared in <root>' type=kotlin.Array<kotlin.String> origin=null
CALL 'public final fun <get-test1> (): kotlin.Array<kotlin.String> declared in <root>' type=kotlin.Array<kotlin.String> origin=null
CONST String type=kotlin.String value="4"
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test3> visibility:public modality:FINAL <> () returnType:kotlin.Array<kotlin.String>
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-test3> visibility:public modality:FINAL <> () returnType:IrErrorType
correspondingProperty: PROPERTY name:test3 visibility:public modality:FINAL [val]
BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-test3> (): kotlin.Array<kotlin.String> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test3 type:kotlin.Array<kotlin.String> visibility:public [final,static] ' type=kotlin.Array<kotlin.String> origin=null
RETURN type=kotlin.Nothing from='public final fun <get-test3> (): IrErrorType declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:test3 type:IrErrorType visibility:public [final,static] ' type=IrErrorType origin=null