From e3122d0c90ca53466142633f808625dbd0fe0116 Mon Sep 17 00:00:00 2001 From: "Denis.Zharkov" Date: Tue, 7 Sep 2021 16:20:36 +0300 Subject: [PATCH] Minor. Extract transformAnonymousFunctionWithExpectedType --- .../FirDeclarationsResolveTransformer.kt | 214 +++++++++--------- 1 file changed, 111 insertions(+), 103 deletions(-) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 2bded80a8eb..17515d7b225 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -705,108 +705,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor buildImplicitTypeRef() } } - val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let { - extractLambdaInfoFromFunctionalType( - it.type, it, anonymousFunction, returnTypeVariable = null, components, candidate = null - ) - } - var lambda = anonymousFunction - val valueParameters = when (resolvedLambdaAtom) { - null -> lambda.valueParameters - else -> { - val singleParameterType = resolvedLambdaAtom.parameters.singleOrNull() - when { - lambda.valueParameters.isEmpty() && singleParameterType != null -> { - val name = Name.identifier("it") - val itParam = buildValueParameter { - source = lambda.source?.fakeElement(FirFakeSourceElementKind.ItLambdaParameter) - moduleData = session.moduleData - origin = FirDeclarationOrigin.Source - returnTypeRef = singleParameterType.toFirResolvedTypeRef() - this.name = name - symbol = FirValueParameterSymbol(name) - isCrossinline = false - isNoinline = false - isVararg = false - } - listOf(itParam) - } - - else -> { - lambda.valueParameters.mapIndexed { index, param -> - if (param.returnTypeRef is FirResolvedTypeRef) { - param - } else { - val resolvedType = - param.returnTypeRef.resolvedTypeFromPrototype(resolvedLambdaAtom.parameters[index]) - param.replaceReturnTypeRef(resolvedType) - param - } - } - } - } - } - } - val returnTypeRefFromResolvedAtom = - resolvedLambdaAtom?.returnType?.let { lambda.returnTypeRef.resolvedTypeFromPrototype(it) } - lambda = lambda.copy( - receiverTypeRef = lambda.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef } - ?: resolvedLambdaAtom?.receiver?.let { lambda.receiverTypeRef?.resolvedTypeFromPrototype(it) }, - valueParameters = valueParameters, - returnTypeRef = (lambda.returnTypeRef as? FirResolvedTypeRef) - ?: returnTypeRefFromResolvedAtom - ?: lambda.returnTypeRef - ) - lambda = lambda.transformValueParameters(ImplicitToErrorTypeTransformer, null) - val bodyExpectedType = returnTypeRefFromResolvedAtom ?: expectedTypeRef - context.withAnonymousFunction(lambda, components, data) { - withFullBodyResolve { - lambda = transformFunction(lambda, withExpectedType(bodyExpectedType)) as FirAnonymousFunction - } - } - // To separate function and separate commit - val writer = FirCallCompletionResultsWriterTransformer( - session, - ConeSubstitutor.Empty, - components.returnTypeCalculator, - inferenceComponents.approximator, - dataFlowAnalyzer, - ) - lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe()?.toExpectedType()) - - val returnStatements = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda) - val returnExpressionsExceptLast = - if (returnStatements.size > 1) - returnStatements - lambda.body?.statements?.lastOrNull() - else - returnStatements - val implicitReturns = returnExpressionsExceptLast.filter { - (it as? FirExpression)?.typeRef is FirImplicitUnitTypeRef - } - val returnType = - if (implicitReturns.isNotEmpty()) { - // i.e., early return, e.g., l@{ ... return@l ... } - // Note that the last statement will be coerced to Unit if needed. - session.builtinTypes.unitType.type - } else { - // Otherwise, compute the common super type of all possible return expressions - inferenceComponents.ctx.commonSuperTypeOrNull( - returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType } - ) ?: session.builtinTypes.unitType.type - } - lambda.replaceReturnTypeRef( - lambda.returnTypeRef.resolvedTypeFromPrototype(returnType).also { - session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null) - } - ) - lambda.replaceTypeRef( - lambda.constructFunctionalTypeRef( - isSuspend = expectedTypeRef.coneTypeSafe()?.isSuspendFunctionType(session) == true - ).also { - session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null) - } - ) - lambda.addReturn() + transformAnonymousFunctionWithExpectedType(anonymousFunction, expectedTypeRef, data) } is ResolutionMode.WithStatus, is ResolutionMode.WithExpectedTypeFromCast -> { throw AssertionError("Should not be here in WithStatus/WithExpectedTypeFromCast mode") @@ -814,6 +713,115 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor } } + private fun transformAnonymousFunctionWithExpectedType( + anonymousFunction: FirAnonymousFunction, + expectedTypeRef: FirTypeRef, + data: ResolutionMode + ): FirAnonymousFunction { + val resolvedLambdaAtom = (expectedTypeRef as? FirResolvedTypeRef)?.let { + extractLambdaInfoFromFunctionalType( + it.type, it, anonymousFunction, returnTypeVariable = null, components, candidate = null + ) + } + var lambda = anonymousFunction + val valueParameters = when (resolvedLambdaAtom) { + null -> lambda.valueParameters + else -> { + val singleParameterType = resolvedLambdaAtom.parameters.singleOrNull() + when { + lambda.valueParameters.isEmpty() && singleParameterType != null -> { + val name = Name.identifier("it") + val itParam = buildValueParameter { + source = lambda.source?.fakeElement(FirFakeSourceElementKind.ItLambdaParameter) + moduleData = session.moduleData + origin = FirDeclarationOrigin.Source + returnTypeRef = singleParameterType.toFirResolvedTypeRef() + this.name = name + symbol = FirValueParameterSymbol(name) + isCrossinline = false + isNoinline = false + isVararg = false + } + listOf(itParam) + } + + else -> { + lambda.valueParameters.mapIndexed { index, param -> + if (param.returnTypeRef is FirResolvedTypeRef) { + param + } else { + val resolvedType = + param.returnTypeRef.resolvedTypeFromPrototype(resolvedLambdaAtom.parameters[index]) + param.replaceReturnTypeRef(resolvedType) + param + } + } + } + } + } + } + val returnTypeRefFromResolvedAtom = + resolvedLambdaAtom?.returnType?.let { lambda.returnTypeRef.resolvedTypeFromPrototype(it) } + lambda = lambda.copy( + receiverTypeRef = lambda.receiverTypeRef?.takeIf { it !is FirImplicitTypeRef } + ?: resolvedLambdaAtom?.receiver?.let { lambda.receiverTypeRef?.resolvedTypeFromPrototype(it) }, + valueParameters = valueParameters, + returnTypeRef = (lambda.returnTypeRef as? FirResolvedTypeRef) + ?: returnTypeRefFromResolvedAtom + ?: lambda.returnTypeRef + ) + lambda = lambda.transformValueParameters(ImplicitToErrorTypeTransformer, null) + val bodyExpectedType = returnTypeRefFromResolvedAtom ?: expectedTypeRef + context.withAnonymousFunction(lambda, components, data) { + withFullBodyResolve { + lambda = transformFunction(lambda, withExpectedType(bodyExpectedType)) as FirAnonymousFunction + } + } + // To separate function and separate commit + val writer = FirCallCompletionResultsWriterTransformer( + session, + ConeSubstitutor.Empty, + components.returnTypeCalculator, + inferenceComponents.approximator, + dataFlowAnalyzer, + ) + lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe()?.toExpectedType()) + + val returnStatements = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(lambda) + val returnExpressionsExceptLast = + if (returnStatements.size > 1) + returnStatements - lambda.body?.statements?.lastOrNull() + else + returnStatements + val implicitReturns = returnExpressionsExceptLast.filter { + (it as? FirExpression)?.typeRef is FirImplicitUnitTypeRef + } + val returnType = + if (implicitReturns.isNotEmpty()) { + // i.e., early return, e.g., l@{ ... return@l ... } + // Note that the last statement will be coerced to Unit if needed. + session.builtinTypes.unitType.type + } else { + // Otherwise, compute the common super type of all possible return expressions + inferenceComponents.ctx.commonSuperTypeOrNull( + returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType } + ) ?: session.builtinTypes.unitType.type + } + lambda.replaceReturnTypeRef( + lambda.returnTypeRef.resolvedTypeFromPrototype(returnType).also { + session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null) + } + ) + lambda.replaceTypeRef( + lambda.constructFunctionalTypeRef( + isSuspend = expectedTypeRef.coneTypeSafe()?.isSuspendFunctionType(session) == true + ).also { + session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, null) + } + ) + return lambda.addReturn() + } + private fun FirAnonymousFunction.addReturn(): FirAnonymousFunction { // If this lambda's resolved, expected return type is Unit, we don't need an explicit return statement. // During conversion (to backend IR), the last expression will be coerced to Unit if needed. @@ -996,4 +1004,4 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor private val FirFunction.bodyResolved: Boolean get() = body !is FirLazyBlock && body?.typeRef is FirResolvedTypeRef -} \ No newline at end of file +}