FIR (WIP): Initial support for proper lambda analysis
This commit is contained in:
committed by
Mikhail Glukhikh
parent
8c67ec8c89
commit
4b5172cda3
@@ -6,12 +6,19 @@
|
|||||||
package org.jetbrains.kotlin.fir
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
|
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirResolvedTypeRefImpl
|
||||||
|
|
||||||
fun FirFunctionCall.copy(
|
fun FirFunctionCall.copy(
|
||||||
annotations: List<FirAnnotationCall> = this.annotations,
|
annotations: List<FirAnnotationCall> = this.annotations,
|
||||||
@@ -36,3 +43,31 @@ fun FirFunctionCall.copy(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirAnonymousFunction.copy(
|
||||||
|
receiverTypeRef: FirTypeRef? = this.receiverTypeRef,
|
||||||
|
psi: PsiElement? = this.psi,
|
||||||
|
session: FirSession = this.session,
|
||||||
|
returnTypeRef: FirTypeRef = this.returnTypeRef,
|
||||||
|
valueParameters: List<FirValueParameter> = this.valueParameters,
|
||||||
|
body: FirBlock? = this.body,
|
||||||
|
annotations: List<FirAnnotationCall> = this.annotations,
|
||||||
|
typeRef: FirTypeRef = this.typeRef,
|
||||||
|
label: FirLabel? = this.label
|
||||||
|
): FirAnonymousFunction {
|
||||||
|
return FirAnonymousFunctionImpl(session, psi, returnTypeRef, receiverTypeRef).apply {
|
||||||
|
this.valueParameters.addAll(valueParameters)
|
||||||
|
this.body = body
|
||||||
|
this.annotations.addAll(annotations)
|
||||||
|
this.typeRef = typeRef
|
||||||
|
this.label = label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun FirTypeRef.resolvedTypeFromPrototype(
|
||||||
|
type: ConeKotlinType
|
||||||
|
): FirResolvedTypeRef {
|
||||||
|
return FirResolvedTypeRefImpl(
|
||||||
|
session, psi, type, false, annotations
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -7,15 +7,13 @@ package org.jetbrains.kotlin.fir.resolve.calls
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
import org.jetbrains.kotlin.fir.declarations.FirValueParameter
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.withNullability
|
import org.jetbrains.kotlin.fir.resolve.withNullability
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
|
|
||||||
|
|
||||||
fun resolveArgumentExpression(
|
fun resolveArgumentExpression(
|
||||||
@@ -31,16 +29,42 @@ fun resolveArgumentExpression(
|
|||||||
expectedType: ConeKotlinType,
|
expectedType: ConeKotlinType,
|
||||||
sink: CheckerSink,
|
sink: CheckerSink,
|
||||||
isReceiver: Boolean,
|
isReceiver: Boolean,
|
||||||
|
acceptLambdaAtoms: (PostponedResolvedAtomMarker) -> Unit,
|
||||||
typeProvider: (FirExpression) -> FirTypeRef?
|
typeProvider: (FirExpression) -> FirTypeRef?
|
||||||
) {
|
) {
|
||||||
return when (argument) {
|
return when (argument) {
|
||||||
is FirQualifiedAccessExpression, is FirFunctionCall -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
is FirQualifiedAccessExpression, is FirFunctionCall -> checkPlainExpressionArgument(
|
||||||
|
csBuilder,
|
||||||
|
argument,
|
||||||
|
expectedType,
|
||||||
|
sink,
|
||||||
|
isReceiver,
|
||||||
|
typeProvider
|
||||||
|
)
|
||||||
// TODO:!
|
// TODO:!
|
||||||
is FirAnonymousFunction -> Unit
|
is FirAnonymousFunction -> preprocessLambdaArgument(csBuilder, argument, expectedType, acceptLambdaAtoms)
|
||||||
// TODO:!
|
// TODO:!
|
||||||
is FirCallableReferenceAccess -> Unit
|
is FirCallableReferenceAccess -> Unit
|
||||||
// TODO:!
|
// TODO:!
|
||||||
//TODO: Collection literal
|
//TODO: Collection literal
|
||||||
|
is FirLambdaArgumentExpression -> resolveArgumentExpression(
|
||||||
|
csBuilder,
|
||||||
|
argument.expression,
|
||||||
|
expectedType,
|
||||||
|
sink,
|
||||||
|
isReceiver,
|
||||||
|
acceptLambdaAtoms,
|
||||||
|
typeProvider
|
||||||
|
)
|
||||||
|
is FirNamedArgumentExpression -> resolveArgumentExpression(
|
||||||
|
csBuilder,
|
||||||
|
argument.expression,
|
||||||
|
expectedType,
|
||||||
|
sink,
|
||||||
|
isReceiver,
|
||||||
|
acceptLambdaAtoms,
|
||||||
|
typeProvider
|
||||||
|
)
|
||||||
else -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
else -> checkPlainExpressionArgument(csBuilder, argument, expectedType, sink, isReceiver, typeProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +103,15 @@ internal fun Candidate.resolveArgument(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
val expectedType = prepareExpectedType(argument, parameter)
|
val expectedType = prepareExpectedType(argument, parameter)
|
||||||
resolveArgumentExpression(this.system.getBuilder(), argument, expectedType, sink, isReceiver, typeProvider)
|
resolveArgumentExpression(
|
||||||
|
this.system.getBuilder(),
|
||||||
|
argument,
|
||||||
|
expectedType,
|
||||||
|
sink,
|
||||||
|
isReceiver,
|
||||||
|
{ this.postponedAtoms += it },
|
||||||
|
typeProvider
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Candidate.prepareExpectedType(argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
|
private fun Candidate.prepareExpectedType(argument: FirExpression, parameter: FirValueParameter): ConeKotlinType {
|
||||||
|
|||||||
+57
-5
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.resolve.calls
|
package org.jetbrains.kotlin.fir.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
@@ -12,9 +14,12 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.TypeVariableDirec
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder
|
import org.jetbrains.kotlin.resolve.calls.inference.components.VariableFixationFinder
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtom
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||||
import org.jetbrains.kotlin.types.model.isIntegerLiteralTypeConstructor
|
import org.jetbrains.kotlin.types.model.isIntegerLiteralTypeConstructor
|
||||||
import org.jetbrains.kotlin.types.model.typeConstructor
|
import org.jetbrains.kotlin.types.model.typeConstructor
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
|
||||||
fun Candidate.computeCompletionMode(
|
fun Candidate.computeCompletionMode(
|
||||||
@@ -68,19 +73,21 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
|||||||
fun complete(
|
fun complete(
|
||||||
c: KotlinConstraintSystemCompleter.Context,
|
c: KotlinConstraintSystemCompleter.Context,
|
||||||
completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode,
|
completionMode: KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode,
|
||||||
candidateReturnType: ConeKotlinType
|
topLevelAtoms: List<FirExpression>,
|
||||||
|
candidateReturnType: ConeKotlinType,
|
||||||
|
analyze: (PostponedResolvedAtomMarker) -> Unit
|
||||||
) {
|
) {
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// if (analyzePostponeArgumentIfPossible(c, topLevelAtoms, analyze)) continue
|
if (analyzePostponeArgumentIfPossible(c, topLevelAtoms, analyze)) continue
|
||||||
|
|
||||||
|
|
||||||
// val allTypeVariables = getOrderedAllTypeVariables(c, collectVariablesFromContext, topLevelAtoms)
|
// val allTypeVariables = getOrderedAllTypeVariables(c, collectVariablesFromContext, topLevelAtoms)
|
||||||
val allTypeVariables = c.notFixedTypeVariables.keys.toList()
|
val allTypeVariables = c.notFixedTypeVariables.keys.toList()
|
||||||
// val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
val postponedKtPrimitives = getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)
|
||||||
val variableForFixation =
|
val variableForFixation =
|
||||||
variableFixationFinder.findFirstVariableForFixation(
|
variableFixationFinder.findFirstVariableForFixation(
|
||||||
c, allTypeVariables, emptyList(), completionMode, candidateReturnType
|
c, allTypeVariables, postponedKtPrimitives, completionMode, candidateReturnType
|
||||||
) ?: break
|
) ?: break
|
||||||
|
|
||||||
// if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) {
|
// if (shouldForceCallableReferenceOrLambdaResolution(completionMode, variableForFixation)) {
|
||||||
@@ -104,7 +111,7 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
|||||||
|
|
||||||
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||||
// force resolution for all not-analyzed argument's
|
// force resolution for all not-analyzed argument's
|
||||||
// getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze)
|
getOrderedNotAnalyzedPostponedArguments(topLevelAtoms).forEach(analyze)
|
||||||
//
|
//
|
||||||
// if (c.notFixedTypeVariables.isNotEmpty() && c.postponedTypeVariables.isEmpty()) {
|
// if (c.notFixedTypeVariables.isNotEmpty() && c.postponedTypeVariables.isEmpty()) {
|
||||||
// runCompletion(c, completionMode, topLevelAtoms, topLevelType, analyze)
|
// runCompletion(c, completionMode, topLevelAtoms, topLevelType, analyze)
|
||||||
@@ -131,4 +138,49 @@ class ConstraintSystemCompleter(val components: InferenceComponents) {
|
|||||||
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
c.fixVariable(variableWithConstraints.typeVariable, resultType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun analyzePostponeArgumentIfPossible(
|
||||||
|
c: KotlinConstraintSystemCompleter.Context,
|
||||||
|
topLevelAtoms: List<FirExpression>,
|
||||||
|
analyze: (PostponedResolvedAtomMarker) -> Unit
|
||||||
|
): Boolean {
|
||||||
|
for (argument in getOrderedNotAnalyzedPostponedArguments(topLevelAtoms)) {
|
||||||
|
if (canWeAnalyzeIt(c, argument)) {
|
||||||
|
analyze(argument)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getOrderedNotAnalyzedPostponedArguments(topLevelAtoms: List<FirExpression>): List<PostponedResolvedAtomMarker> {
|
||||||
|
fun FirExpression.process(to: MutableList<PostponedResolvedAtomMarker>) {
|
||||||
|
when (this) {
|
||||||
|
is FirFunctionCall -> {
|
||||||
|
val candidate = (this.calleeReference as? FirNamedReferenceWithCandidate)?.candidate
|
||||||
|
candidate?.postponedAtoms?.forEach {
|
||||||
|
to.addIfNotNull(it.safeAs<PostponedResolvedAtomMarker>()?.takeUnless { it.analyzed })
|
||||||
|
}
|
||||||
|
this.arguments.forEach { it.process(to) }
|
||||||
|
}
|
||||||
|
// TOOD: WTF?
|
||||||
|
}
|
||||||
|
// if (analyzed) {
|
||||||
|
// subResolvedAtoms.forEach { it.process(to) }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
val notAnalyzedArguments = arrayListOf<PostponedResolvedAtomMarker>()
|
||||||
|
for (primitive in topLevelAtoms) {
|
||||||
|
primitive.process(notAnalyzedArguments)
|
||||||
|
}
|
||||||
|
|
||||||
|
return notAnalyzedArguments
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun canWeAnalyzeIt(c: KotlinConstraintSystemCompleter.Context, argument: PostponedResolvedAtomMarker): Boolean {
|
||||||
|
if (argument.analyzed) return false
|
||||||
|
|
||||||
|
return argument.inputTypes.all { c.containsOnlyFixedOrPostponedVariables(it) }
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+167
@@ -0,0 +1,167 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
|
fun preprocessLambdaArgument(
|
||||||
|
csBuilder: ConstraintSystemBuilder,
|
||||||
|
argument: FirAnonymousFunction,
|
||||||
|
expectedType: ConeKotlinType?,
|
||||||
|
acceptLambdaAtoms: (PostponedResolvedAtomMarker) -> Unit,
|
||||||
|
forceResolution: Boolean = false
|
||||||
|
) {
|
||||||
|
if (expectedType != null && !forceResolution && csBuilder.isTypeVariable(expectedType)) {
|
||||||
|
//return LambdaWithTypeVariableAsExpectedTypeAtom(argument, expectedType)
|
||||||
|
}
|
||||||
|
|
||||||
|
val resolvedArgument = extractLambdaInfoFromFunctionalType(expectedType, argument) ?: extraLambdaInfo(expectedType, argument, csBuilder)
|
||||||
|
|
||||||
|
if (expectedType != null) {
|
||||||
|
// val lambdaType = createFunctionType(
|
||||||
|
// csBuilder.builtIns, Annotations.EMPTY, resolvedArgument.receiver,
|
||||||
|
// resolvedArgument.parameters, null, resolvedArgument.returnType, resolvedArgument.isSuspend
|
||||||
|
// )
|
||||||
|
// csBuilder.addSubtypeConstraint(lambdaType, expectedType, ArgumentConstraintPosition(argument))
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptLambdaAtoms(resolvedArgument)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val ConeKotlinType.isBuiltinFunctionalType: Boolean
|
||||||
|
get () {
|
||||||
|
val type = this
|
||||||
|
return when (type) {
|
||||||
|
is ConeClassType -> type.lookupTag.classId.asString().startsWith("kotlin/Function")
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private val ConeKotlinType.isSuspendFunctionType: Boolean
|
||||||
|
get() {
|
||||||
|
val type = this
|
||||||
|
return when (type) {
|
||||||
|
is ConeClassType -> {
|
||||||
|
val classId = type.lookupTag.classId
|
||||||
|
classId.packageFqName.asString() == "kotlin" && classId.relativeClassName.asString().startsWith("SuspendFunction")
|
||||||
|
}
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ConeKotlinType.receiverType: ConeKotlinType? get() = null
|
||||||
|
private val ConeKotlinType.returnType: ConeKotlinType
|
||||||
|
get() {
|
||||||
|
require(this is ConeClassType)
|
||||||
|
val projection = typeArguments.last()
|
||||||
|
require(projection is ConeTypedProjection)
|
||||||
|
return projection.type
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ConeKotlinType.valueParameterTypes: List<ConeKotlinType?>
|
||||||
|
get() {
|
||||||
|
require(this is ConeClassType)
|
||||||
|
return typeArguments.dropLast(1).map {
|
||||||
|
(it as? ConeTypedProjection)?.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val FirAnonymousFunction.returnType get() = returnTypeRef.coneTypeSafe<ConeKotlinType>()
|
||||||
|
private val FirAnonymousFunction.receiverType get() = receiverTypeRef?.coneTypeSafe<ConeKotlinType>()
|
||||||
|
|
||||||
|
|
||||||
|
private fun extraLambdaInfo(
|
||||||
|
expectedType: ConeKotlinType?,
|
||||||
|
argument: FirAnonymousFunction,
|
||||||
|
csBuilder: ConstraintSystemBuilder
|
||||||
|
): ResolvedLambdaAtom {
|
||||||
|
// val builtIns = csBuilder.builtIns
|
||||||
|
val isSuspend = expectedType?.isSuspendFunctionType ?: false
|
||||||
|
|
||||||
|
val isFunctionSupertype =
|
||||||
|
expectedType != null && expectedType.isBuiltinFunctionalType//isNotNullOrNullableFunctionSupertype(expectedType)
|
||||||
|
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
|
||||||
|
|
||||||
|
val typeVariable = TypeVariableForLambdaReturnType(argument, "_L")
|
||||||
|
|
||||||
|
val receiverType = null//argumentAsFunctionExpression?.receiverType
|
||||||
|
val returnType =
|
||||||
|
argumentAsFunctionExpression?.returnType
|
||||||
|
?: expectedType?.typeArguments?.singleOrNull()?.safeAs<ConeTypedProjection>()?.type?.takeIf { isFunctionSupertype }
|
||||||
|
?: typeVariable.defaultType
|
||||||
|
|
||||||
|
val parameters = argument.valueParameters?.map { it.returnTypeRef.coneTypeSafe<ConeKotlinType>() ?: TODO("!nothing") } ?: emptyList()
|
||||||
|
|
||||||
|
val newTypeVariableUsed = returnType == typeVariable.defaultType
|
||||||
|
if (newTypeVariableUsed) csBuilder.registerVariable(typeVariable)
|
||||||
|
|
||||||
|
return ResolvedLambdaAtom(argument, isSuspend, receiverType, parameters, returnType, typeVariable.takeIf { newTypeVariableUsed })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractLambdaInfoFromFunctionalType(expectedType: ConeKotlinType?, argument: FirAnonymousFunction): ResolvedLambdaAtom? {
|
||||||
|
if (expectedType == null || !expectedType.isBuiltinFunctionalType) return null
|
||||||
|
val parameters = extractLambdaParameters(expectedType, argument)
|
||||||
|
|
||||||
|
val argumentAsFunctionExpression = argument//.safeAs<FunctionExpression>()
|
||||||
|
val receiverType = argumentAsFunctionExpression?.receiverType ?: expectedType.receiverType
|
||||||
|
val returnType = argumentAsFunctionExpression?.returnType ?: expectedType.returnType
|
||||||
|
|
||||||
|
return ResolvedLambdaAtom(
|
||||||
|
argument,
|
||||||
|
expectedType.isSuspendFunctionType,
|
||||||
|
receiverType,
|
||||||
|
parameters,
|
||||||
|
returnType,
|
||||||
|
typeVariableForLambdaReturnType = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractLambdaParameters(expectedType: ConeKotlinType, argument: FirAnonymousFunction): List<ConeKotlinType> {
|
||||||
|
val parameters = argument.valueParameters
|
||||||
|
val expectedParameters = expectedType.valueParameterTypes
|
||||||
|
if (parameters.isEmpty()) {
|
||||||
|
return expectedParameters.map { it?.type ?: TODO("any?") }
|
||||||
|
}
|
||||||
|
|
||||||
|
return parameters.mapIndexed { index, parameter ->
|
||||||
|
parameter.returnTypeRef.coneTypeSafe() ?: expectedParameters.getOrNull(index) ?: TODO("any?")//expectedType.builtIns.nullableAnyType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TypeVariableForLambdaReturnType(val argument: FirAnonymousFunction, name: String) : ConeTypeVariable(name)
|
||||||
|
|
||||||
|
|
||||||
|
class ResolvedLambdaAtom(
|
||||||
|
val atom: FirAnonymousFunction,
|
||||||
|
val isSuspend: Boolean,
|
||||||
|
val receiver: ConeKotlinType?,
|
||||||
|
val parameters: List<ConeKotlinType>,
|
||||||
|
val returnType: ConeKotlinType,
|
||||||
|
val typeVariableForLambdaReturnType: TypeVariableForLambdaReturnType?
|
||||||
|
) : PostponedResolvedAtomMarker {
|
||||||
|
|
||||||
|
override var analyzed: Boolean = false
|
||||||
|
|
||||||
|
// lateinit var resultArguments: List<KotlinCallArgument>
|
||||||
|
// private set
|
||||||
|
|
||||||
|
// fun setAnalyzedResults(
|
||||||
|
// resultArguments: List<KotlinCallArgument>,
|
||||||
|
// subResolvedAtoms: List<ResolvedAtom>
|
||||||
|
// ) {
|
||||||
|
// this.resultArguments = resultArguments
|
||||||
|
// setAnalyzedResults(subResolvedAtoms)
|
||||||
|
// }
|
||||||
|
|
||||||
|
override val inputTypes: Collection<ConeKotlinType> get() = receiver?.let { parameters + it } ?: parameters
|
||||||
|
override val outputType: ConeKotlinType get() = returnType
|
||||||
|
}
|
||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. 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.resolve.calls
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.constructType
|
||||||
|
import org.jetbrains.kotlin.fir.service
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.StandardClassIds.Unit
|
||||||
|
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.model.SimpleConstraintSystemConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.PostponedResolvedAtomMarker
|
||||||
|
import org.jetbrains.kotlin.types.model.*
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.invoke
|
||||||
|
|
||||||
|
interface LambdaAnalyzer {
|
||||||
|
fun analyzeAndGetLambdaReturnArguments(
|
||||||
|
lambdaArgument: FirAnonymousFunction,
|
||||||
|
isSuspend: Boolean,
|
||||||
|
receiverType: ConeKotlinType?,
|
||||||
|
parameters: List<ConeKotlinType>,
|
||||||
|
expectedReturnType: ConeKotlinType?, // null means, that return type is not proper i.e. it depends on some type variables
|
||||||
|
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
||||||
|
): Pair<List<FirExpression>, InferenceSession>
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class PostponedArgumentsAnalyzer(
|
||||||
|
val lambdaAnalyzer: LambdaAnalyzer,
|
||||||
|
val typeProvider: (FirExpression) -> FirTypeRef?,
|
||||||
|
val session: FirSession
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun analyze(
|
||||||
|
c: PostponedArgumentsAnalyzer.Context,
|
||||||
|
// resolutionCallbacks: KotlinResolutionCallbacks,
|
||||||
|
argument: PostponedResolvedAtomMarker
|
||||||
|
//diagnosticsHolder: KotlinDiagnosticsHolder
|
||||||
|
) {
|
||||||
|
when (argument) {
|
||||||
|
is ResolvedLambdaAtom ->
|
||||||
|
analyzeLambda(c, argument/*, diagnosticsHolder*/)
|
||||||
|
|
||||||
|
// is LambdaWithTypeVariableAsExpectedTypeAtom ->
|
||||||
|
// analyzeLambda(
|
||||||
|
// c, resolutionCallbacks, argument.transformToResolvedLambda(c.getBuilder()), diagnosticsHolder
|
||||||
|
// )
|
||||||
|
|
||||||
|
// is ResolvedCallableReferenceAtom ->
|
||||||
|
// callableReferenceResolver.processCallableReferenceArgument(c.getBuilder(), argument, diagnosticsHolder)
|
||||||
|
//
|
||||||
|
// is ResolvedCollectionLiteralAtom -> TODO("Not supported")
|
||||||
|
|
||||||
|
else -> error("Unexpected resolved primitive: ${argument.javaClass.canonicalName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun analyzeLambda(
|
||||||
|
c: PostponedArgumentsAnalyzer.Context,
|
||||||
|
lambda: ResolvedLambdaAtom//,
|
||||||
|
//diagnosticHolder: KotlinDiagnosticsHolder
|
||||||
|
) {
|
||||||
|
val unitType = Unit(session.service()).constructType(emptyArray(), false)
|
||||||
|
val stubsForPostponedVariables = c.bindingStubsForPostponedVariables()
|
||||||
|
val currentSubstitutor = c.buildCurrentSubstitutor(stubsForPostponedVariables.mapKeys { it.key.freshTypeConstructor(c) })
|
||||||
|
|
||||||
|
fun substitute(type: ConeKotlinType) = currentSubstitutor.safeSubstitute(c, type) as ConeKotlinType
|
||||||
|
|
||||||
|
val receiver = lambda.receiver?.let(::substitute)
|
||||||
|
val parameters = lambda.parameters.map(::substitute)
|
||||||
|
val rawReturnType = lambda.returnType
|
||||||
|
|
||||||
|
val expectedTypeForReturnArguments = when {
|
||||||
|
c.canBeProper(rawReturnType) -> substitute(rawReturnType)
|
||||||
|
|
||||||
|
// For Unit-coercion
|
||||||
|
c.hasUpperOrEqualUnitConstraint(rawReturnType) -> unitType
|
||||||
|
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
val (returnArguments, inferenceSession) = lambdaAnalyzer.analyzeAndGetLambdaReturnArguments(
|
||||||
|
lambda.atom,
|
||||||
|
lambda.isSuspend,
|
||||||
|
receiver,
|
||||||
|
parameters,
|
||||||
|
expectedTypeForReturnArguments,
|
||||||
|
stubsForPostponedVariables
|
||||||
|
)
|
||||||
|
|
||||||
|
returnArguments.forEach { c.addSubsystemFromExpression(it) }
|
||||||
|
|
||||||
|
val checkerSink: CheckerSink = CheckerSinkImpl()
|
||||||
|
|
||||||
|
val subResolvedKtPrimitives = returnArguments.map {
|
||||||
|
var atom: PostponedResolvedAtomMarker? = null
|
||||||
|
resolveArgumentExpression(
|
||||||
|
c.getBuilder(),
|
||||||
|
it,
|
||||||
|
lambda.returnType.let(::substitute),
|
||||||
|
checkerSink,
|
||||||
|
false,
|
||||||
|
{ atom = it },
|
||||||
|
typeProvider
|
||||||
|
)
|
||||||
|
// resolveKtPrimitive(
|
||||||
|
// c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, isReceiver = false
|
||||||
|
// )
|
||||||
|
}
|
||||||
|
|
||||||
|
if (returnArguments.isEmpty()) {
|
||||||
|
// val unitType =
|
||||||
|
val lambdaReturnType = lambda.returnType.let(::substitute)
|
||||||
|
c.getBuilder().addSubtypeConstraint(
|
||||||
|
lambdaReturnType,
|
||||||
|
unitType, /*LambdaArgumentConstraintPosition(lambda)*/
|
||||||
|
SimpleConstraintSystemConstraintPosition
|
||||||
|
)
|
||||||
|
c.getBuilder().addSubtypeConstraint(
|
||||||
|
unitType,
|
||||||
|
lambdaReturnType, /*LambdaArgumentConstraintPosition(lambda)*/
|
||||||
|
SimpleConstraintSystemConstraintPosition
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
lambda.analyzed = true
|
||||||
|
//lambda.setAnalyzedResults(returnArguments, subResolvedKtPrimitives)
|
||||||
|
|
||||||
|
// if (inferenceSession != null) {
|
||||||
|
// val storageSnapshot = c.getBuilder().currentStorage()
|
||||||
|
//
|
||||||
|
// val postponedVariables = inferenceSession.inferPostponedVariables(lambda, storageSnapshot)
|
||||||
|
//
|
||||||
|
// for ((constructor, resultType) in postponedVariables) {
|
||||||
|
// val variableWithConstraints = storageSnapshot.notFixedTypeVariables[constructor] ?: continue
|
||||||
|
// val variable = variableWithConstraints.typeVariable
|
||||||
|
//
|
||||||
|
// c.getBuilder().unmarkPostponedVariable(variable)
|
||||||
|
// c.getBuilder().addEqualityConstraint(variable.defaultType(c), resultType, CoroutinePosition())
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+130
-1
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve.transformers
|
|||||||
import com.google.common.collect.LinkedHashMultimap
|
import com.google.common.collect.LinkedHashMultimap
|
||||||
import org.jetbrains.kotlin.fir.*
|
import org.jetbrains.kotlin.fir.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl
|
||||||
import org.jetbrains.kotlin.fir.expressions.*
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
import org.jetbrains.kotlin.resolve.calls.NewCommonSuperTypeCalculator
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.InferenceSession
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
import org.jetbrains.kotlin.resolve.calls.inference.buildAbstractResultingSubstitutor
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||||
@@ -249,6 +251,40 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
return transformCallee(variableAssignment).compose()
|
return transformCallee(variableAssignment).compose()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun transformAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Any?): CompositeTransformResult<FirDeclaration> {
|
||||||
|
if (data == null) return anonymousFunction.compose()
|
||||||
|
if (data is LambdaResolution) return transformAnonymousFunction(anonymousFunction, data).compose()
|
||||||
|
return super.transformAnonymousFunction(anonymousFunction, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun transformAnonymousFunction(anonymousFunction: FirAnonymousFunction, lambdaResolution: LambdaResolution): FirAnonymousFunction {
|
||||||
|
val receiverTypeRef = anonymousFunction.receiverTypeRef
|
||||||
|
fun transform(): FirAnonymousFunction {
|
||||||
|
return withScopeCleanup(scopes) {
|
||||||
|
scopes.addIfNotNull(receiverTypeRef?.coneTypeSafe()?.scope(session, ScopeSession()))
|
||||||
|
val result =
|
||||||
|
super.transformAnonymousFunction(
|
||||||
|
anonymousFunction,
|
||||||
|
lambdaResolution.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef
|
||||||
|
).single as FirAnonymousFunction
|
||||||
|
val body = result.body
|
||||||
|
if (result.returnTypeRef is FirImplicitTypeRef && body != null) {
|
||||||
|
result.transformReturnTypeRef(this, body.resultType)
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val label = anonymousFunction.label
|
||||||
|
return if (label != null && receiverTypeRef != null) {
|
||||||
|
withLabel(Name.identifier(label.name), receiverTypeRef.coneTypeUnsafe()) { transform() }
|
||||||
|
} else {
|
||||||
|
transform()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
private fun resolveCallAndSelectCandidate(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
||||||
|
|
||||||
val functionCall = functionCall.transformChildren(this, null) as FirFunctionCall
|
val functionCall = functionCall.transformChildren(this, null) as FirFunctionCall
|
||||||
@@ -314,6 +350,8 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
return resultExpression
|
return resultExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class LambdaResolution(val expectedReturnTypeRef: FirResolvedTypeRef?)
|
||||||
|
|
||||||
private fun completeTypeInference(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
private fun completeTypeInference(functionCall: FirFunctionCall, expectedTypeRef: FirTypeRef?): FirFunctionCall {
|
||||||
val typeRef = typeFromCallee(functionCall)
|
val typeRef = typeFromCallee(functionCall)
|
||||||
if (typeRef.type is ConeKotlinErrorType) {
|
if (typeRef.type is ConeKotlinErrorType) {
|
||||||
@@ -327,7 +365,61 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn
|
|||||||
|
|
||||||
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
|
val completionMode = candidate.computeCompletionMode(inferenceComponents, expectedTypeRef, initialType)
|
||||||
val completer = ConstraintSystemCompleter(inferenceComponents)
|
val completer = ConstraintSystemCompleter(inferenceComponents)
|
||||||
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, initialType)
|
val replacements = mutableMapOf<FirExpression, FirExpression>()
|
||||||
|
|
||||||
|
val analyzer = PostponedArgumentsAnalyzer(object : LambdaAnalyzer {
|
||||||
|
override fun analyzeAndGetLambdaReturnArguments(
|
||||||
|
lambdaArgument: FirAnonymousFunction,
|
||||||
|
isSuspend: Boolean,
|
||||||
|
receiverType: ConeKotlinType?,
|
||||||
|
parameters: List<ConeKotlinType>,
|
||||||
|
expectedReturnType: ConeKotlinType?,
|
||||||
|
stubsForPostponedVariables: Map<TypeVariableMarker, StubTypeMarker>
|
||||||
|
): Pair<List<FirExpression>, InferenceSession> {
|
||||||
|
|
||||||
|
val itParam = when {
|
||||||
|
lambdaArgument.valueParameters.isEmpty() && parameters.size == 1 ->
|
||||||
|
FirValueParameterImpl(
|
||||||
|
session,
|
||||||
|
null,
|
||||||
|
Name.identifier("it"),
|
||||||
|
FirResolvedTypeRefImpl(session, null, parameters.single(), false, emptyList()),
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
val newLambdaExpression = lambdaArgument.copy(
|
||||||
|
receiverTypeRef = receiverType?.let { lambdaArgument.receiverTypeRef!!.resolvedTypeFromPrototype(it) },
|
||||||
|
valueParameters = lambdaArgument.valueParameters.mapIndexed { index, parameter ->
|
||||||
|
parameter.transformReturnTypeRef(StoreType, parameter.returnTypeRef.resolvedTypeFromPrototype(parameters[index]))
|
||||||
|
parameter
|
||||||
|
} + listOfNotNull(itParam)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
val expectedReturnTypeRef = expectedReturnType?.let { newLambdaExpression.returnTypeRef.resolvedTypeFromPrototype(it) }
|
||||||
|
replacements[lambdaArgument] =
|
||||||
|
newLambdaExpression.transformSingle(this@FirBodyResolveTransformer, LambdaResolution(expectedReturnTypeRef))
|
||||||
|
|
||||||
|
|
||||||
|
return listOfNotNull(newLambdaExpression.body?.statements?.lastOrNull() as? FirExpression) to InferenceSession.default
|
||||||
|
}
|
||||||
|
|
||||||
|
}, { it.resultType }, session)
|
||||||
|
|
||||||
|
completer.complete(candidate.system.asConstraintSystemCompleterContext(), completionMode, listOf(functionCall), initialType) {
|
||||||
|
analyzer.analyze(
|
||||||
|
candidate.system.asPostponedArgumentsAnalyzerContext(),
|
||||||
|
it
|
||||||
|
// diagnosticsHolder
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
functionCall.transformChildren(ReplaceInArguments, replacements.toMap())
|
||||||
|
|
||||||
|
|
||||||
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
if (completionMode == KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.FULL) {
|
||||||
@@ -712,4 +804,41 @@ private object StoreNameReference : FirTransformer<FirNamedReference>() {
|
|||||||
): CompositeTransformResult<FirNamedReference> {
|
): CompositeTransformResult<FirNamedReference> {
|
||||||
return data.compose()
|
return data.compose()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object StoreType : FirTransformer<FirResolvedTypeRef>() {
|
||||||
|
override fun <E : FirElement> transformElement(element: E, data: FirResolvedTypeRef): CompositeTransformResult<E> {
|
||||||
|
return element.compose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformTypeRef(typeRef: FirTypeRef, data: FirResolvedTypeRef): CompositeTransformResult<FirTypeRef> {
|
||||||
|
return data.compose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ReplaceInArguments : FirTransformer<Map<FirElement, FirElement>>() {
|
||||||
|
override fun <E : FirElement> transformElement(element: E, data: Map<FirElement, FirElement>): CompositeTransformResult<E> {
|
||||||
|
return ((data[element] ?: element) as E).compose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformFunctionCall(
|
||||||
|
functionCall: FirFunctionCall,
|
||||||
|
data: Map<FirElement, FirElement>
|
||||||
|
): CompositeTransformResult<FirStatement> {
|
||||||
|
return (functionCall.transformChildren(this, data) as FirStatement).compose()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun transformNamedArgumentExpression(
|
||||||
|
namedArgumentExpression: FirNamedArgumentExpression,
|
||||||
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+26
-77
@@ -6,122 +6,71 @@ FILE: lambda.kt
|
|||||||
public final fun baz(f: R|kotlin/Function0<kotlin/Unit>|, other: R|kotlin/Boolean| = Boolean(true)): R|kotlin/Unit| {
|
public final fun baz(f: R|kotlin/Function0<kotlin/Unit>|, other: R|kotlin/Boolean| = Boolean(true)): R|kotlin/Unit| {
|
||||||
}
|
}
|
||||||
public final fun test(): R|kotlin/Unit| {
|
public final fun test(): R|kotlin/Unit| {
|
||||||
R|/foo|(<L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
R|/foo|(<L> = foo@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/foo|(<L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
R|/foo|(<L> = foo@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/foo|(foo@fun <implicit>.<anonymous>(): <implicit> {
|
R|/foo|(foo@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(Int(1), <L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(Int(1), <L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(f = foo@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/foo]>#(f = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
, <L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
, <L> = foo@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/bar|(Int(1), <L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
R|/bar|(Int(1), <L> = bar@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/bar|(x = Int(1), <L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
R|/bar|(x = Int(1), <L> = bar@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/bar|(Int(1), bar@fun <implicit>.<anonymous>(): <implicit> {
|
R|/bar|(Int(1), bar@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/bar|(x = Int(1), f = bar@fun <implicit>.<anonymous>(): <implicit> {
|
R|/bar|(x = Int(1), f = bar@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(<L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(<L> = bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(bar@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/bar]>#(bar@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/baz|(other = Boolean(false), f = baz@fun <implicit>.<anonymous>(): <implicit> {
|
R|/baz|(other = Boolean(false), f = baz@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
R|/baz|(baz@fun <implicit>.<anonymous>(): <implicit> {
|
R|/baz|(baz@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
, Boolean(false))
|
, Boolean(false))
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(<L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(<L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(<L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(<L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(other = Boolean(false), <L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
<Inapplicable(PARAMETER_MAPPING_ERROR): [/baz]>#(other = Boolean(false), <L> = baz@fun <implicit>.<anonymous>(): <implicit> {
|
||||||
^ {
|
Unit
|
||||||
Unit
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
fun foo(block: () -> Unit) {}
|
||||||
|
fun bar(block: () -> String) {}
|
||||||
|
fun itIs(block: (String) -> String) {}
|
||||||
|
fun multipleArgs(block: (String, String) -> String) {}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
foo { "This is test" }
|
||||||
|
bar { "This is also test" }
|
||||||
|
itIs { "this is $it test" }
|
||||||
|
multipleArgs { a, b -> "This is test of $a, $b" }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FILE: lambda.kt
|
||||||
|
public final fun foo(block: R|kotlin/Function0<kotlin/Unit>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun bar(block: R|kotlin/Function0<kotlin/String>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun itIs(block: R|kotlin/Function1<kotlin/String, kotlin/String>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun multipleArgs(block: R|kotlin/Function2<kotlin/String, kotlin/String, kotlin/String>|): R|kotlin/Unit| {
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|/foo|(<L> = foo@fun <anonymous>(): R|kotlin/Unit| {
|
||||||
|
String(This is test)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
R|/bar|(<L> = bar@fun <anonymous>(): R|kotlin/String| {
|
||||||
|
String(This is also test)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
R|/itIs|(<L> = itIs@fun <anonymous>(it: R|kotlin/String|): R|kotlin/String| {
|
||||||
|
<strcat>(String(this is ), R|<local>/it|, String( test))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
R|/multipleArgs|(<L> = multipleArgs@fun <anonymous>(a: R|kotlin/String|, b: R|kotlin/String|): R|kotlin/String| {
|
||||||
|
<strcat>(String(This is test of ), R|<local>/a|, String(, ), R|<local>/b|)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,17 +1,11 @@
|
|||||||
FILE: functionX.kt
|
FILE: functionX.kt
|
||||||
public final val x: R|kotlin/jvm/functions/Function0<kotlin/Int>| = fun R|kotlin/jvm/functions/Function0<kotlin/Int>|.<anonymous>(): R|kotlin/jvm/functions/Function0<kotlin/Int>| {
|
public final val x: R|kotlin/jvm/functions/Function0<kotlin/Int>| = fun R|kotlin/jvm/functions/Function0<kotlin/Int>|.<anonymous>(): R|kotlin/jvm/functions/Function0<kotlin/Int>| {
|
||||||
^ {
|
Int(42)
|
||||||
Int(42)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(): R|kotlin/jvm/functions/Function0<kotlin/Int>|
|
public get(): R|kotlin/jvm/functions/Function0<kotlin/Int>|
|
||||||
public final val y: R|kotlin/Function1<kotlin/String, kotlin/String>| = fun R|kotlin/Function1<kotlin/String, kotlin/String>|.<anonymous>(): R|kotlin/Function1<kotlin/String, kotlin/String>| {
|
public final val y: R|kotlin/Function1<kotlin/String, kotlin/String>| = fun R|kotlin/Function1<kotlin/String, kotlin/String>|.<anonymous>(): R|kotlin/Function1<kotlin/String, kotlin/String>| {
|
||||||
^ {
|
<Unresolved name: it>#
|
||||||
<Unresolved name: it>#
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(): R|kotlin/Function1<kotlin/String, kotlin/String>|
|
public get(): R|kotlin/Function1<kotlin/String, kotlin/String>|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun main() {
|
||||||
|
val x = List(10) {
|
||||||
|
"number = $it"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
FILE: mapList.kt
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
lval x: R|kotlin/collections/List<kotlin/String>| = R|kotlin/collections/List|<R|kotlin/String|>(Int(10), <L> = List@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/String| {
|
||||||
|
<strcat>(String(number = ), R|<local>/it|)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
+5
@@ -212,6 +212,11 @@ public class FirResolveTestCaseGenerated extends AbstractFirResolveTestCase {
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/dispatchReceiver.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/dispatchReceiver.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("lambda.kt")
|
||||||
|
public void testLambda() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/lambda.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("localImplicitBodies.kt")
|
@TestMetadata("localImplicitBodies.kt")
|
||||||
public void testLocalImplicitBodies() throws Exception {
|
public void testLocalImplicitBodies() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/expresssions/localImplicitBodies.kt");
|
runTest("compiler/fir/resolve/testData/resolve/expresssions/localImplicitBodies.kt");
|
||||||
|
|||||||
Generated
+5
@@ -44,6 +44,11 @@ public class FirResolveTestCaseWithStdlibGenerated extends AbstractFirResolveTes
|
|||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/helloWorld.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/helloWorld.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("mapList.kt")
|
||||||
|
public void testMapList() throws Exception {
|
||||||
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/mapList.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("reflectionClass.kt")
|
@TestMetadata("reflectionClass.kt")
|
||||||
public void testReflectionClass() throws Exception {
|
public void testReflectionClass() throws Exception {
|
||||||
runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt");
|
runTest("compiler/fir/resolve/testData/resolve/stdlib/reflectionClass.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user