Minor. Extract transformAnonymousFunctionWithExpectedType
This commit is contained in:
committed by
teamcityserver
parent
226893c648
commit
e3122d0c90
+111
-103
@@ -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<ConeKotlinType>()?.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<ConeKotlinType>()?.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<ConeKotlinType>()?.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<ConeKotlinType>()?.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
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user