From 803abfeba836b502cdc41c2b9f14300790d5ce1c Mon Sep 17 00:00:00 2001 From: pyos Date: Thu, 8 Dec 2022 12:02:43 +0100 Subject: [PATCH] FIR: rewrite lambda return type inference * `return` should only be added to the last statement if the return type is not Unit * If there is a `return` without an argument, then the expected return type is Unit and the last expression is not a return argument (unless it's an incomplete call, in which case it is inferred to return Unit; this behavior is questionable, but inherited from K1) * There should be a constraint on return arguments even if the expected type is Unit, otherwise errors will be missed * When the expected type is known, using the call completion results writer is pointless (and probably subtly wrong). ^KT-54742 Fixed --- ...kotlin_dom_api_compat_1_8_255_SNAPSHOT.xml | 8 + .../invoke/threeReceiversCorrect.fir.txt | 4 +- .../coercionToUnitWithEarlyReturn.fir.txt | 2 +- .../receivers/implicitReceivers.fir.txt | 2 +- .../basic.fir.txt | 2 +- .../basic.kt | 2 +- .../kotlin/fir/resolve/ResolveUtils.kt | 35 +++ .../fir/resolve/calls/CandidateFactory.kt | 14 +- .../inference/PostponedArgumentsAnalyzer.kt | 28 ++- ...rCallCompletionResultsWriterTransformer.kt | 82 +++---- .../FirDeclarationsResolveTransformer.kt | 218 +++++------------- .../ifToAnyDiscriminatingUsages.fir.kt | 2 +- .../coercionToUnit/afterBareReturn.fir.kt | 2 +- .../postponedArgumentsAnalysis/basic.fir.kt | 4 +- ...esolveCollectionLiteralInsideLambda.fir.kt | 4 +- .../suspendFunctions.fir.kt | 4 +- .../functionalType.fir.ir.txt | 149 ++++++------ .../functionalType.fir.kt.txt | 2 +- .../contextReceivers/lazy.fir.ir.txt | 160 ------------- .../contextReceivers/lazy.fir.kt.txt | 54 ----- .../declarations/contextReceivers/lazy.kt | 1 + 21 files changed, 241 insertions(+), 538 deletions(-) create mode 100644 .idea/artifacts/kotlin_dom_api_compat_1_8_255_SNAPSHOT.xml delete mode 100644 compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.ir.txt delete mode 100644 compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.kt.txt diff --git a/.idea/artifacts/kotlin_dom_api_compat_1_8_255_SNAPSHOT.xml b/.idea/artifacts/kotlin_dom_api_compat_1_8_255_SNAPSHOT.xml new file mode 100644 index 00000000000..76279d18930 --- /dev/null +++ b/.idea/artifacts/kotlin_dom_api_compat_1_8_255_SNAPSHOT.xml @@ -0,0 +1,8 @@ + + + $PROJECT_DIR$/libraries/kotlin-dom-api-compat/build/libs + + + + + \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceiversCorrect.fir.txt b/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceiversCorrect.fir.txt index d2e9e007b0d..04bff26682d 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceiversCorrect.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/invoke/threeReceiversCorrect.fir.txt @@ -31,9 +31,9 @@ FILE: threeReceiversCorrect.kt (this@R|special/anonymous|, R|/b|).R|/A.foo|.R|SubstitutionOverride|(R|/c|) } ) - ^ R|/with|(R|/b|, = with@fun R|B|.(): R|kotlin/Unit| { + R|/with|(R|/b|, = with@fun R|B|.(): R|kotlin/Unit| { (this@R|special/anonymous|, this@R|special/anonymous|).R|/A.foo|.R|SubstitutionOverride|(R|/c|) - ^ R|/with|(R|/c|, = with@fun R|C|.(): R|kotlin/Unit| { + R|/with|(R|/c|, = with@fun R|C|.(): R|kotlin/Unit| { (this@R|special/anonymous|, this@R|special/anonymous|).R|/A.foo|.R|SubstitutionOverride|(this@R|special/anonymous|) } ) diff --git a/compiler/fir/analysis-tests/testData/resolve/inference/coercionToUnitWithEarlyReturn.fir.txt b/compiler/fir/analysis-tests/testData/resolve/inference/coercionToUnitWithEarlyReturn.fir.txt index aa2e21b484d..17f9b7a04b7 100644 --- a/compiler/fir/analysis-tests/testData/resolve/inference/coercionToUnitWithEarlyReturn.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/inference/coercionToUnitWithEarlyReturn.fir.txt @@ -18,7 +18,7 @@ FILE: coercionToUnitWithEarlyReturn.kt } } - ^ R|/x|?.{ $subj$.R|/A.unit|() } + R|/x|?.{ $subj$.R|/A.unit|() } } R|/foo|(R|/lambda|) diff --git a/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceivers.fir.txt b/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceivers.fir.txt index e6e8b67dbf5..a4008d940d7 100644 --- a/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceivers.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolve/smartcasts/receivers/implicitReceivers.fir.txt @@ -51,7 +51,7 @@ FILE: implicitReceivers.kt } public final fun test_3(a: R|kotlin/Any|, b: R|kotlin/Any|, c: R|kotlin/Any|): R|kotlin/Unit| { R|kotlin/with|(R|/a|, = wa@fun R|kotlin/Any|.(): R|kotlin/Unit| { - ^ R|kotlin/with|(R|/b|, = wb@fun R|kotlin/Any|.(): R|kotlin/Unit| { + R|kotlin/with|(R|/b|, = wb@fun R|kotlin/Any|.(): R|kotlin/Unit| { R|kotlin/with|(R|/c|, = wc@fun R|kotlin/Any|.(): R|kotlin/Unit| { (this@R|special/anonymous| as R|A|) this@R|special/anonymous|.R|/A.foo|() diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.fir.txt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.fir.txt index 1e9a515cd7b..a3b5ff1ffe0 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.fir.txt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.fir.txt @@ -48,7 +48,7 @@ FILE: basic.kt foo@fun (): R|kotlin/Unit| { ^@foo Unit } - .R|/foo|(foo@fun R|A|.(): R|kotlin/Unit| { + .R|/foo#|(foo@fun R|A|.(): R|kotlin/Unit| { this@R|special/anonymous|.R|/A.bar|() ^@foo Int(10) } diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt index 2ce0b1ab128..06f8aea7865 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/diagnostics/functionReturnTypeMismatchChecker/basic.kt @@ -37,7 +37,7 @@ fun errorWithLambda(): String { return@foo } foo { bar() - return@foo 10 + return@foo 10 } return "" diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt index 95b125106bd..6db901cc88b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/ResolveUtils.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.* +import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirSuperReference @@ -48,6 +49,7 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.impl.ConeClassLikeTypeImpl +import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.StandardClassIds @@ -63,6 +65,39 @@ import kotlin.contracts.contract fun List.toTypeProjections(): Array = asReversed().flatMap { it.typeArgumentList.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray() +fun FirAnonymousFunction.shouldReturnUnit(returnStatements: Collection): Boolean = + isLambda && returnStatements.any { it is FirUnitExpression } + +fun FirAnonymousFunction.isExplicitlySuspend(session: FirSession): Boolean = + typeRef.coneTypeSafe()?.isSuspendFunctionType(session) == true + +fun FirAnonymousFunction.addReturnToLastStatementIfNeeded() { + // 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. + if (returnTypeRef.isUnit) return + + val body = this.body ?: return + val lastStatement = body.statements.lastOrNull() as? FirExpression ?: return + if (lastStatement is FirReturnExpression) return + + val returnType = (body.typeRef as? FirResolvedTypeRef) ?: return + if (returnType.isNothing || returnType.isUnit) return + + val returnTarget = FirFunctionTarget(null, isLambda = isLambda).also { it.bind(this) } + val returnExpression = buildReturnExpression { + source = lastStatement.source?.fakeElement(KtFakeSourceElementKind.ImplicitReturn.FromLastStatement) + result = lastStatement + target = returnTarget + } + body.transformStatements( + object : FirTransformer() { + override fun transformElement(element: E, data: Nothing?): E = + @Suppress("UNCHECKED_CAST") + if (element == lastStatement) returnExpression as E else element + }, null + ) +} + fun FirFunction.constructFunctionalType(isSuspend: Boolean = false): ConeLookupTagBasedType { val receiverTypeRef = when (this) { is FirSimpleFunction -> receiverParameter diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt index 5567953cbf2..48af548d5ff 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/CandidateFactory.kt @@ -167,18 +167,22 @@ class CandidateFactory private constructor( } } -fun PostponedArgumentsAnalyzerContext.addSubsystemFromExpression(statement: FirStatement) { - when (statement) { +fun PostponedArgumentsAnalyzerContext.addSubsystemFromExpression(statement: FirStatement): Boolean { + return when (statement) { is FirQualifiedAccessExpression, is FirWhenExpression, is FirTryExpression, is FirCheckNotNullCall, - is FirElvisExpression - -> (statement as FirResolvable).candidate()?.let { addOtherSystem(it.system.asReadOnlyStorage()) } + is FirElvisExpression -> { + val candidate = (statement as FirResolvable).candidate() ?: return false + addOtherSystem(candidate.system.asReadOnlyStorage()) + true + } is FirSafeCallExpression -> addSubsystemFromExpression(statement.selector) is FirWrappedArgumentExpression -> addSubsystemFromExpression(statement.expression) - is FirBlock -> statement.returnExpressions().forEach { addSubsystemFromExpression(it) } + is FirBlock -> statement.returnExpressions().any { addSubsystemFromExpression(it) } + else -> false } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt index 367ccfa2dec..567dca4bd72 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/inference/PostponedArgumentsAnalyzer.kt @@ -14,12 +14,12 @@ import org.jetbrains.kotlin.fir.references.builder.buildErrorNamedReference import org.jetbrains.kotlin.fir.resolve.calls.* import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnresolvedReferenceError import org.jetbrains.kotlin.fir.resolve.inference.model.ConeLambdaArgumentConstraintPosition +import org.jetbrains.kotlin.fir.resolve.shouldReturnUnit import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.ConeTypeVariable import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.coneType import org.jetbrains.kotlin.fir.types.isMarkedNullable import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzerContext import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder @@ -170,23 +170,29 @@ class PostponedArgumentsAnalyzer( ) { val (returnArguments, inferenceSession) = results - returnArguments.forEach { c.addSubsystemFromExpression(it) } val checkerSink: CheckerSink = CheckerSinkImpl(candidate) val builder = c.getBuilder() val lastExpression = lambda.atom.body?.statements?.lastOrNull() as? FirExpression var hasExpressionInReturnArguments = false - // No constraint for return expressions of lambda if it has Unit return type. - val lambdaReturnType = lambda.returnType.let(substitute).takeUnless { it.isUnitOrFlexibleUnit } + val lambdaReturnType = lambda.returnType.let(substitute) returnArguments.forEach { + val haveSubsystem = c.addSubsystemFromExpression(it) if (it !is FirExpression) return@forEach + // If the lambda returns Unit, the last expression is not returned and should not be constrained. + // TODO (KT-55837) questionable moment inherited from FE1.0 (the `haveSubsystem` case): + // fun foo(): T + // run { + // if (p) return@run + // foo() // T = Unit, even though there is no implicit return + // } + // Things get even weirder if T has an upper bound incompatible with Unit. + if (it == lastExpression && !haveSubsystem && + (expectedReturnType?.isUnitOrFlexibleUnit == true || lambda.atom.shouldReturnUnit(returnArguments)) + ) return@forEach + hasExpressionInReturnArguments = true - // If it is the last expression, and the expected type is Unit, that expression will be coerced to Unit. - // If the last expression is of Unit type, of course it's not coercion-to-Unit case. - val lastExpressionCoercedToUnit = - it == lastExpression && expectedReturnType?.isUnitOrFlexibleUnit == true && !it.typeRef.coneType.isUnitOrFlexibleUnit - // No constraint for the last expression of lambda if it will be coerced to Unit. - if (!lastExpressionCoercedToUnit && !builder.hasContradiction) { + if (!builder.hasContradiction) { candidate.resolveArgumentExpression( builder, it, @@ -200,7 +206,7 @@ class PostponedArgumentsAnalyzer( } } - if (!hasExpressionInReturnArguments && lambdaReturnType != null) { + if (!hasExpressionInReturnArguments && !lambdaReturnType.isUnitOrFlexibleUnit) { builder.addSubtypeConstraint( components.session.builtinTypes.unitType.type, lambdaReturnType, 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 4e646cc172e..443af40bfc3 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 @@ -42,7 +42,6 @@ import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef import org.jetbrains.kotlin.fir.types.builder.buildStarProjection import org.jetbrains.kotlin.fir.types.builder.buildTypeProjectionWithVariance import org.jetbrains.kotlin.fir.types.impl.ConeTypeParameterTypeImpl -import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle @@ -575,12 +574,10 @@ class FirCallCompletionResultsWriterTransformer( anonymousFunction: FirAnonymousFunction, data: ExpectedArgumentType?, ): FirStatement { - // This case is not common, and happens when there are anonymous function arguments that aren't mapped to any parameter in the call - // So, we don't run body resolve transformation for them, thus there's no control flow info either - // Control flow info is necessary prerequisite because we collect return expressions in that function - // - // Example: second lambda in the call like list.filter({}, {}) - val returnExpressionsOfAnonymousFunction = dataFlowAnalyzer.returnExpressionsOfAnonymousFunctionOrNull(anonymousFunction) + // The case where we can't find any return expressions not common, and happens when there are anonymous function arguments + // that aren't mapped to any parameter in the call. So, we don't run body resolve transformation for them, thus there's + // no control flow info either. Example: second lambda in the call like list.filter({}, {}) + val returnStatements = dataFlowAnalyzer.returnExpressionsOfAnonymousFunctionOrNull(anonymousFunction) ?: return transformImplicitTypeRefInAnonymousFunction(anonymousFunction) val expectedType = data?.getExpectedType(anonymousFunction)?.let { expectedArgumentType -> @@ -609,7 +606,7 @@ class FirCallCompletionResultsWriterTransformer( } } - var needUpdateLambdaType = false + var needUpdateLambdaType = anonymousFunction.typeRef is FirImplicitTypeRef val receiverParameter = anonymousFunction.receiverParameter val initialReceiverType = receiverParameter?.typeRef?.coneTypeSafe() @@ -619,64 +616,39 @@ class FirCallCompletionResultsWriterTransformer( needUpdateLambdaType = true } - val initialType = anonymousFunction.returnTypeRef.coneTypeSafe() + val initialReturnType = anonymousFunction.returnTypeRef.coneTypeSafe() + val expectedReturnType = initialReturnType?.let { finalSubstitutor.substituteOrSelf(it) } + ?: expectedType?.returnType(session) as? ConeClassLikeType + ?: (data as? ExpectedArgumentType.ArgumentsMap)?.lambdasReturnTypes?.get(anonymousFunction) - val finalType = if (anonymousFunction.isLambda) { - expectedType?.returnType(session) as? ConeClassLikeType - ?: (data as? ExpectedArgumentType.ArgumentsMap)?.lambdasReturnTypes?.get(anonymousFunction) - ?: initialType?.let(finalSubstitutor::substituteOrSelf) - } else { - initialType?.let(finalSubstitutor::substituteOrSelf) - ?: expectedType?.returnType(session) as? ConeClassLikeType - ?: (data as? ExpectedArgumentType.ArgumentsMap)?.lambdasReturnTypes?.get(anonymousFunction) + val newData = expectedReturnType?.toExpectedType() + val result = transformElement(anonymousFunction, newData) + for (expression in returnStatements) { + expression.transformSingle(this, newData) } - if (finalType != null) { - if (anonymousFunction.returnTypeRef !is FirImplicitUnitTypeRef) { - val resultType = anonymousFunction.returnTypeRef.withReplacedConeType(finalType) - anonymousFunction.replaceReturnTypeRef(resultType) - } + // Prefer the expected type over the inferred one - the latter is a subtype of the former in valid code, + // and there will be ARGUMENT_TYPE_MISMATCH errors on the lambda's return expressions in invalid code. + val resultReturnType = expectedReturnType + ?: session.typeContext.commonSuperTypeOrNull(returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType }) + ?: session.builtinTypes.unitType.type + + if (initialReturnType != resultReturnType) { + result.replaceReturnTypeRef(result.returnTypeRef.resolvedTypeFromPrototype(resultReturnType)) + session.lookupTracker?.recordTypeResolveAsLookup(result.returnTypeRef, result.source, context.file.source) needUpdateLambdaType = true } if (needUpdateLambdaType) { - val resolvedTypeRef = - anonymousFunction.constructFunctionalTypeRef( - isSuspend = expectedType?.isSuspendFunctionType(session) == true || - (expectedType == null && anonymousFunction.isSuspendFunctionType()) - ) - anonymousFunction.replaceTypeRef(resolvedTypeRef) - session.lookupTracker?.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, context.file.source) + val isSuspend = expectedType?.isSuspendFunctionType(session) ?: result.isExplicitlySuspend(session) + result.replaceTypeRef(result.constructFunctionalTypeRef(isSuspend)) + session.lookupTracker?.recordTypeResolveAsLookup(result.typeRef, result.source, context.file.source) } - - val result = transformElement(anonymousFunction, null) - - for (expression in returnExpressionsOfAnonymousFunction) { - expression.transform(this, finalType?.toExpectedType()) - } - - if (result.returnTypeRef.coneTypeSafe() != null) { - val lastExpressionType = - (returnExpressionsOfAnonymousFunction.lastOrNull() as? FirExpression) - ?.typeRef?.coneTypeSafe() - - val newReturnTypeRef = result.returnTypeRef.withReplacedConeType(lastExpressionType) - result.replaceReturnTypeRef(newReturnTypeRef) - val resolvedTypeRef = - result.constructFunctionalTypeRef(isSuspend = expectedType?.isSuspendFunctionType(session) == true) - result.replaceTypeRef(resolvedTypeRef) - session.lookupTracker?.let { - it.recordTypeResolveAsLookup(newReturnTypeRef, anonymousFunction.source, context.file.source) - it.recordTypeResolveAsLookup(resolvedTypeRef, anonymousFunction.source, context.file.source) - } - } - + // Have to delay this until the type is written to avoid adding a return if the type is Unit. + result.addReturnToLastStatementIfNeeded() return result } - private fun FirAnonymousFunction.isSuspendFunctionType() = - typeRef.coneTypeSafe()?.isSuspendFunctionType(session) == true - private fun transformImplicitTypeRefInAnonymousFunction( anonymousFunction: FirAnonymousFunction ): FirStatement { 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 69ebd386f84..a8815fe7552 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 @@ -22,8 +22,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind import org.jetbrains.kotlin.fir.expressions.* -import org.jetbrains.kotlin.fir.expressions.builder.buildReturnExpression -import org.jetbrains.kotlin.fir.expressions.builder.buildUnitExpression import org.jetbrains.kotlin.fir.expressions.impl.FirLazyBlock import org.jetbrains.kotlin.fir.references.FirResolvedErrorReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference @@ -36,7 +34,6 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeLocalVariableNoTypeOrIni import org.jetbrains.kotlin.fir.resolve.inference.FirStubTypeTransformer import org.jetbrains.kotlin.fir.resolve.inference.ResolvedLambdaAtom import org.jetbrains.kotlin.fir.resolve.inference.extractLambdaInfoFromFunctionalType -import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.createTypeSubstitutorByTypeConstructor import org.jetbrains.kotlin.fir.resolve.transformers.FirCallCompletionResultsWriterTransformer import org.jetbrains.kotlin.fir.resolve.transformers.FirStatusResolver @@ -49,8 +46,6 @@ import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.builder.buildErrorTypeRef import org.jetbrains.kotlin.fir.types.builder.buildImplicitTypeRef import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef -import org.jetbrains.kotlin.fir.types.impl.FirImplicitUnitTypeRef -import org.jetbrains.kotlin.fir.visitors.FirDefaultTransformer import org.jetbrains.kotlin.fir.visitors.FirTransformer import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.name.Name @@ -590,34 +585,6 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve return result } - private fun transformAnonymousFunctionWithLambdaResolution( - anonymousFunction: FirAnonymousFunction, lambdaResolution: ResolutionMode.LambdaResolution - ): FirAnonymousFunction { - val expectedReturnType = - lambdaResolution.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef.takeUnless { it is FirImplicitTypeRef } - val result = transformFunction(anonymousFunction, withExpectedType(expectedReturnType)) as FirAnonymousFunction - val body = result.body - if (result.returnTypeRef is FirImplicitTypeRef && body != null) { - // TODO: This part seems unnecessary because for lambdas in dependent context will be completed and their type - // should be replaced there properly - val returnType = - dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(result) - .firstNotNullOfOrNull { (it as? FirExpression)?.resultType?.coneTypeSafe() } - val resolutionMode = if (returnType != null) { - withExpectedType(returnType) - } else { - withExpectedType(buildErrorTypeRef { - diagnostic = - ConeSimpleDiagnostic("Unresolved lambda return type", DiagnosticKind.InferenceError) - }) - } - - result.transformReturnTypeRef(transformer, resolutionMode) - } - - return result - } - override fun transformSimpleFunction( simpleFunction: FirSimpleFunction, data: ResolutionMode @@ -785,39 +752,40 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve return when (data) { is ResolutionMode.ContextDependent, is ResolutionMode.ContextDependentDelegate -> { context.withAnonymousFunction(anonymousFunction, components, data) { - anonymousFunction.addReturn() + anonymousFunction } } is ResolutionMode.LambdaResolution -> { - context.withAnonymousFunction(anonymousFunction, components, data) { - withFullBodyResolve { - transformAnonymousFunctionWithLambdaResolution(anonymousFunction, data).addReturn() - } - } + val expectedReturnTypeRef = + data.expectedReturnTypeRef ?: anonymousFunction.returnTypeRef.takeUnless { it is FirImplicitTypeRef } + transformAnonymousFunctionBody(anonymousFunction, expectedReturnTypeRef, data) } - is ResolutionMode.WithExpectedType, - is ResolutionMode.ContextIndependent, - is ResolutionMode.ReceiverResolution, - is ResolutionMode.WithSuggestedType -> { - val expectedTypeRef = when (data) { - is ResolutionMode.WithExpectedType -> { - data.expectedTypeRef - } - is ResolutionMode.WithSuggestedType -> { - data.suggestedTypeRef - } - else -> { - buildImplicitTypeRef() - } - } - transformAnonymousFunctionWithExpectedType(anonymousFunction, expectedTypeRef, data) - } - is ResolutionMode.WithStatus, is ResolutionMode.WithExpectedTypeFromCast -> { + is ResolutionMode.WithExpectedType -> + transformAnonymousFunctionWithExpectedType(anonymousFunction, data.expectedTypeRef, data) + is ResolutionMode.WithSuggestedType -> + transformAnonymousFunctionWithExpectedType(anonymousFunction, data.suggestedTypeRef, data) + is ResolutionMode.ContextIndependent, is ResolutionMode.ReceiverResolution -> + transformAnonymousFunctionWithExpectedType(anonymousFunction, buildImplicitTypeRef(), data) + is ResolutionMode.WithStatus, is ResolutionMode.WithExpectedTypeFromCast -> throw AssertionError("Should not be here in WithStatus/WithExpectedTypeFromCast mode") - } } } + + private fun transformAnonymousFunctionBody( + anonymousFunction: FirAnonymousFunction, + expectedReturnTypeRef: FirTypeRef?, + data: ResolutionMode + ): FirAnonymousFunction { + // `transformFunction` will replace both `typeRef` and `returnTypeRef`, so make sure to keep the former. + val lambdaType = anonymousFunction.typeRef + return context.withAnonymousFunction(anonymousFunction, components, data) { + withFullBodyResolve { + transformFunction(anonymousFunction, withExpectedType(expectedReturnTypeRef)) as FirAnonymousFunction + } + }.apply { replaceTypeRef(lambdaType) } + } + private fun transformAnonymousFunctionWithExpectedType( anonymousFunction: FirAnonymousFunction, expectedTypeRef: FirTypeRef, @@ -829,12 +797,10 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve ) } var lambda = anonymousFunction - val initialReturnTypeRef = lambda.returnTypeRef val valueParameters = when { resolvedLambdaAtom != null -> obtainValueParametersFromResolvedLambdaAtom(resolvedLambdaAtom, lambda) else -> obtainValueParametersFromExpectedType(expectedTypeRef.coneTypeSafe(), lambda) } - val returnTypeRefFromResolvedAtom = resolvedLambdaAtom?.returnType?.let { lambda.returnTypeRef.resolvedTypeFromPrototype(it) } lambda = buildAnonymousFunctionCopy(lambda) { receiverParameter = lambda.receiverParameter?.takeIf { it.typeRef !is FirImplicitTypeRef } ?: resolvedLambdaAtom?.receiver?.let { coneKotlinType -> @@ -857,71 +823,38 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve this.valueParameters.clear() this.valueParameters.addAll(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, - session.typeApproximator, - dataFlowAnalyzer, - components.integerLiteralAndOperatorApproximationTransformer, - components.context - ) - lambda.transformSingle(writer, expectedTypeRef.coneTypeSafe()?.toExpectedType()) + }.transformValueParameters(ImplicitToErrorTypeTransformer, null) - 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 initialReturnTypeRef = lambda.returnTypeRef as? FirResolvedTypeRef + val expectedReturnTypeRef = initialReturnTypeRef + ?: resolvedLambdaAtom?.returnType?.let { lambda.returnTypeRef.resolvedTypeFromPrototype(it) } + lambda = transformAnonymousFunctionBody(lambda, expectedReturnTypeRef ?: components.noExpectedType, data) + + if (initialReturnTypeRef == null) { + lambda.replaceReturnTypeRef(lambda.computeReturnTypeRef(expectedReturnTypeRef)) + session.lookupTracker?.recordTypeResolveAsLookup(lambda.returnTypeRef, lambda.source, context.file.source) } - val returnType = when { - initialReturnTypeRef is FirResolvedTypeRef -> { - initialReturnTypeRef.coneType - } - implicitReturns.isNotEmpty() || (lambda.returnType?.isUnit == true && lambda.isLambda) -> { - // i.e., early return, e.g., l@{ ... return@l ... } - // Note that the last statement will be coerced to Unit if needed. - // also we don't coerce to Unit anonymous functions, only lambdas - session.builtinTypes.unitType.type - } - else -> { - // Otherwise, compute the common super type of all possible return expressions - session.typeContext.commonSuperTypeOrNull( - returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType } - ) ?: session.builtinTypes.unitType.type - } - } - if (lambda.returnTypeRef !is FirImplicitUnitTypeRef) { - lambda.replaceReturnTypeRef( - initialReturnTypeRef.resolvedTypeFromPrototype(returnType).also { - session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, components.file.source) - } - ) - } - lambda.replaceTypeRef( - lambda.constructFunctionalTypeRef( - isSuspend = expectedTypeRef.coneTypeSafe()?.isSuspendFunctionType(session) == true - ).also { - session.lookupTracker?.recordTypeResolveAsLookup(it, lambda.source, components.file.source) - } - ) - return lambda.addReturn() + lambda.replaceTypeRef(lambda.constructFunctionalTypeRef(resolvedLambdaAtom?.isSuspend == true)) + session.lookupTracker?.recordTypeResolveAsLookup(lambda.typeRef, lambda.source, context.file.source) + lambda.addReturnToLastStatementIfNeeded() + return lambda + } + + private fun FirAnonymousFunction.computeReturnTypeRef(expected: FirResolvedTypeRef?): FirResolvedTypeRef { + // Any lambda expression assigned to `(...) -> Unit` returns Unit + if (isLambda && expected?.type?.isUnit == true) return expected + // `lambda@ { return@lambda }` always returns Unit + val returnStatements = dataFlowAnalyzer.returnExpressionsOfAnonymousFunction(this) + if (shouldReturnUnit(returnStatements)) return session.builtinTypes.unitType + // Here is a questionable moment where we could prefer the expected type over an inferred one. + // In correct code this doesn't matter, as all return expression types should be subtypes of the expected type. + // In incorrect code, this would change diagnostics: we can get errors either on the entire lambda, or only on its + // return statements. The former kind of makes more sense, but the latter is more readable. + val inferredFromReturnStatements = + session.typeContext.commonSuperTypeOrNull(returnStatements.mapNotNull { (it as? FirExpression)?.resultType?.coneType }) + return inferredFromReturnStatements?.let { returnTypeRef.resolvedTypeFromPrototype(it) } + ?: session.builtinTypes.unitType // Empty lambda returns Unit } private fun obtainValueParametersFromResolvedLambdaAtom( @@ -982,47 +915,6 @@ open class FirDeclarationsResolveTransformer(transformer: FirAbstractBodyResolve } } - 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. - // As per KT-41005, we should not force coercion to Unit for nullable return type, though. - if (returnTypeRef.isUnit && body?.typeRef?.isMarkedNullable == false) { - return this - } - val lastStatement = body?.statements?.lastOrNull() - val returnType = (body?.typeRef as? FirResolvedTypeRef) ?: return this - val returnNothing = returnType.isNothing || returnType.isUnit - if (lastStatement is FirExpression && !returnNothing) { - body?.transformChildren( - object : FirDefaultTransformer() { - override fun transformElement(element: E, data: FirExpression): E { - if (element == lastStatement) { - val returnExpression = buildReturnExpression { - source = element.source?.fakeElement(KtFakeSourceElementKind.ImplicitReturn.FromLastStatement) - result = lastStatement - target = FirFunctionTarget(null, isLambda = this@addReturn.isLambda).also { - it.bind(this@addReturn) - } - } - @Suppress("UNCHECKED_CAST") - return (returnExpression as E) - } - return element - } - - override fun transformReturnExpression( - returnExpression: FirReturnExpression, - data: FirExpression - ): FirStatement { - return returnExpression - } - }, - buildUnitExpression() - ) - } - return this - } - override fun transformBackingField( backingField: FirBackingField, data: ResolutionMode, diff --git a/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt b/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt index e1ada18d66e..1eb65c77223 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/ifToAnyDiscriminatingUsages.fir.kt @@ -27,7 +27,7 @@ fun testResultOfAnonFun2() = fun testReturnFromAnonFun() = run(fun () { - return if (true) 42 else println() + return if (true) 42 else println() }) fun testReturn1() = diff --git a/compiler/testData/diagnostics/tests/inference/coercionToUnit/afterBareReturn.fir.kt b/compiler/testData/diagnostics/tests/inference/coercionToUnit/afterBareReturn.fir.kt index 974ddc2e21f..2b90328b8ab 100644 --- a/compiler/testData/diagnostics/tests/inference/coercionToUnit/afterBareReturn.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/coercionToUnit/afterBareReturn.fir.kt @@ -34,7 +34,7 @@ fun test4() = run { fun main() { // all ok - expectUnit(test1()) + expectUnit(test1()) expectUnit(test2()) expectUnit(test3()) expectUnit(test4()) diff --git a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt index 78caf68098d..db821b0f188 100644 --- a/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/completion/postponedArgumentsAnalysis/basic.fir.kt @@ -139,8 +139,8 @@ fun main() { * K <: (C) -> Unit -> TypeVariable(_RP1) >: C * K == (B) -> Unit -> TypeVariable(_RP1) == B */ - val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) - val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) + val x17: (C) -> Unit = selectB(id { it }, id { it }, id<(B) -> Unit> { x -> x }) + val x18: (C) -> Unit = select(id { it }, { it }, id<(B) -> Unit> { x -> x }) // Resolution of extension/non-extension functions combination val x19: String.() -> Unit = select(")!>id { this }, ")!>id(fun(x: String) {})) diff --git a/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt b/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt index 320ab3f96a4..13064873389 100644 --- a/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt +++ b/compiler/testData/diagnostics/tests/regressions/resolveCollectionLiteralInsideLambda.fir.kt @@ -3,5 +3,5 @@ fun foo(l: () -> Unit) {} fun bar(l: () -> String) {} -val a = foo { [] } -val b = bar { [] } +val a = foo { [] } +val b = bar { [] } diff --git a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt index 7d960f86839..1520a1d44a4 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/inference/completion/postponedArgumentsAnalysis/suspendFunctions.fir.kt @@ -19,7 +19,7 @@ fun main() { val x1: suspend (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) // Here, the error should be - val x2: (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) - val x3: suspend (Int) -> Unit = takeSimpleFunction(")!>id { it }, ")!>{ x -> x }) + val x2: (Int) -> Unit = takeSuspend(")!>id { it }, ")!>{ x -> x }) + val x3: suspend (Int) -> Unit = takeSimpleFunction(")!>id { it }, ")!>{ x -> x }) val x4: (Int) -> Unit = takeSimpleFunction(id Unit> {}, ")!>{}) } diff --git a/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.ir.txt b/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.ir.txt index ae2b6af8cdf..ea1bd615300 100644 --- a/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.ir.txt +++ b/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.ir.txt @@ -172,78 +172,77 @@ FILE fqName: fileName:/functionalType.kt FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.C) returnType:kotlin.Unit $receiver: VALUE_PARAMETER name:$this$with type:.C BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .test' - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .R - : kotlin.Unit - receiver: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .R' type=.R origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.R, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.R) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.R - BLOCK_BODY - CALL 'public final fun f1 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: GET_VAR 'val lf1: @[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit> [val] declared in .test' type=@[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit> origin=null - CALL 'public final fun f1 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.R, _context_receiver_0:.C, :.Param) returnType:kotlin.Unit - contextReceiverParametersCount: 1 - $receiver: VALUE_PARAMETER name:$this$f1 type:.R - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C - VALUE_PARAMETER UNDERSCORE_PARAMETER name: index:1 type:.Param - BLOCK_BODY - TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - CALL 'public final fun (): kotlin.Int declared in .R' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR '$this$f1: .R declared in .test...' type=.R origin=null - TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - CALL 'public final fun f2 (_context_receiver_0: .C, g: kotlin.Function2<.C, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: GET_VAR 'val lf2: kotlin.Function2<.C, .Param, kotlin.Unit> [val] declared in .test' type=kotlin.Function2<.C, .Param, kotlin.Unit> origin=null - CALL 'public final fun f2 (_context_receiver_0: .C, g: kotlin.Function2<.C, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: FUN_EXPR type=kotlin.Function2<.C, .Param, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (_context_receiver_0:.C, :.Param) returnType:kotlin.Unit - contextReceiverParametersCount: 1 - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C - VALUE_PARAMETER UNDERSCORE_PARAMETER name: index:1 type:.Param - BLOCK_BODY - TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - CALL 'public final fun f3 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: GET_VAR 'val lf3: @[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit> [val] declared in .test' type=@[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit> origin=null - CALL 'public final fun f3 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.R, _context_receiver_0:.C) returnType:kotlin.Unit - contextReceiverParametersCount: 1 - $receiver: VALUE_PARAMETER name:$this$f3 type:.R - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C - BLOCK_BODY - TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - CALL 'public final fun (): kotlin.Int declared in .R' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR '$this$f3: .R declared in .test...' type=.R origin=null - TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - CALL 'public final fun f4 (_context_receiver_0: .C, g: kotlin.Function1<.C, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: GET_VAR 'val lf4: kotlin.Function1<.C, kotlin.Unit> [val] declared in .test' type=kotlin.Function1<.C, kotlin.Unit> origin=null - CALL 'public final fun f4 (_context_receiver_0: .C, g: kotlin.Function1<.C, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null - g: FUN_EXPR type=kotlin.Function1<.C, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (_context_receiver_0:.C) returnType:kotlin.Unit - contextReceiverParametersCount: 1 - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C - BLOCK_BODY - TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit - CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY - $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null + : .R + : kotlin.Unit + receiver: CONSTRUCTOR_CALL 'public constructor () [primary] declared in .R' type=.R origin=null + block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.R, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.R) returnType:kotlin.Unit + $receiver: VALUE_PARAMETER name:$this$with type:.R + BLOCK_BODY + CALL 'public final fun f1 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: GET_VAR 'val lf1: @[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit> [val] declared in .test' type=@[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit> origin=null + CALL 'public final fun f1 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function3<.C, .R, .Param, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.R, _context_receiver_0:.C, :.Param) returnType:kotlin.Unit + contextReceiverParametersCount: 1 + $receiver: VALUE_PARAMETER name:$this$f1 type:.R + VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C + VALUE_PARAMETER UNDERSCORE_PARAMETER name: index:1 type:.Param + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.Int declared in .R' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '$this$f1: .R declared in .test...' type=.R origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + CALL 'public final fun f2 (_context_receiver_0: .C, g: kotlin.Function2<.C, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: GET_VAR 'val lf2: kotlin.Function2<.C, .Param, kotlin.Unit> [val] declared in .test' type=kotlin.Function2<.C, .Param, kotlin.Unit> origin=null + CALL 'public final fun f2 (_context_receiver_0: .C, g: kotlin.Function2<.C, .Param, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: FUN_EXPR type=kotlin.Function2<.C, .Param, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (_context_receiver_0:.C, :.Param) returnType:kotlin.Unit + contextReceiverParametersCount: 1 + VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C + VALUE_PARAMETER UNDERSCORE_PARAMETER name: index:1 type:.Param + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + CALL 'public final fun f3 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: GET_VAR 'val lf3: @[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit> [val] declared in .test' type=@[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit> origin=null + CALL 'public final fun f3 (_context_receiver_0: .C, g: @[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + $receiver: GET_VAR '$this$with: .R declared in .test..' type=.R origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function2<.C, .R, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.R, _context_receiver_0:.C) returnType:kotlin.Unit + contextReceiverParametersCount: 1 + $receiver: VALUE_PARAMETER name:$this$f3 type:.R + VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.Int declared in .R' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '$this$f3: .R declared in .test...' type=.R origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + CALL 'public final fun f4 (_context_receiver_0: .C, g: kotlin.Function1<.C, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: GET_VAR 'val lf4: kotlin.Function1<.C, kotlin.Unit> [val] declared in .test' type=kotlin.Function1<.C, kotlin.Unit> origin=null + CALL 'public final fun f4 (_context_receiver_0: .C, g: kotlin.Function1<.C, kotlin.Unit>): kotlin.Unit declared in ' type=kotlin.Unit origin=null + _context_receiver_0: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null + g: FUN_EXPR type=kotlin.Function1<.C, kotlin.Unit> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> (_context_receiver_0:.C) returnType:kotlin.Unit + contextReceiverParametersCount: 1 + VALUE_PARAMETER name:_context_receiver_0 index:0 type:.C + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun (): kotlin.Int declared in .C' type=kotlin.Int origin=GET_PROPERTY + $this: GET_VAR '$this$with: .C declared in .test.' type=.C origin=null diff --git a/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.kt.txt b/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.kt.txt index 478a6ced6b7..f8ab7ef373e 100644 --- a/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.kt.txt +++ b/compiler/testData/ir/irText/declarations/contextReceivers/functionalType.fir.kt.txt @@ -69,7 +69,7 @@ fun test() { } with(receiver = C(), block = local fun C.() { - return with(receiver = R(), block = local fun R.() { + with(receiver = R(), block = local fun R.() { $this$with.f1(_context_receiver_0 = $this$with, g = lf1) $this$with.f1(_context_receiver_0 = $this$with, g = local fun R.(_context_receiver_0: C, : Param) { $this$f1.() /*~> Unit */ diff --git a/compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.ir.txt b/compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.ir.txt deleted file mode 100644 index 1fd6b7c0a90..00000000000 --- a/compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.ir.txt +++ /dev/null @@ -1,160 +0,0 @@ -FILE fqName: fileName:/lazy.kt - CLASS INTERFACE name:Lazy modality:ABSTRACT visibility:public superTypes:[kotlin.Any] - $this: VALUE_PARAMETER INSTANCE_RECEIVER name: type:.Lazy.Lazy> - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false - FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN <> ($this:kotlin.Any, other:kotlin.Any?) returnType:kotlin.Boolean [fake_override,operator] - overridden: - public open fun equals (other: kotlin.Any?): kotlin.Boolean [operator] declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - VALUE_PARAMETER name:other index:0 type:kotlin.Any? - FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.Int [fake_override] - overridden: - public open fun hashCode (): kotlin.Int declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN <> ($this:kotlin.Any) returnType:kotlin.String [fake_override] - overridden: - public open fun toString (): kotlin.String declared in kotlin.Any - $this: VALUE_PARAMETER name: type:kotlin.Any - FUN name:test1 visibility:public modality:FINAL <> (_context_receiver_0:.Lazy, _context_receiver_1:.Lazy) returnType:kotlin.Unit - contextReceiverParametersCount: 2 - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.Lazy - VALUE_PARAMETER name:_context_receiver_1 index:1 type:.Lazy - BLOCK_BODY - FUN name:test2 visibility:public modality:FINAL ($receiver:.Lazy, _context_receiver_0:.Lazy.test2>) returnType:kotlin.Unit - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false - contextReceiverParametersCount: 1 - $receiver: VALUE_PARAMETER name: type:.Lazy - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.Lazy.test2> - BLOCK_BODY - FUN name:test3 visibility:public modality:FINAL ($receiver:.Lazy, _context_receiver_0:.Lazy<.Lazy.test3>>) returnType:kotlin.Unit - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false - contextReceiverParametersCount: 1 - $receiver: VALUE_PARAMETER name: type:.Lazy - VALUE_PARAMETER name:_context_receiver_0 index:0 type:.Lazy<.Lazy.test3>> - BLOCK_BODY - FUN name:f visibility:public modality:FINAL (lazy1:.Lazy, lazy2:.Lazy, lazyT:.Lazy.f>, lazyLazyT:.Lazy<.Lazy.f>>) returnType:kotlin.Unit - TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false - VALUE_PARAMETER name:lazy1 index:0 type:.Lazy - VALUE_PARAMETER name:lazy2 index:1 type:.Lazy - VALUE_PARAMETER name:lazyT index:2 type:.Lazy.f> - VALUE_PARAMETER name:lazyLazyT index:3 type:.Lazy<.Lazy.f>> - BLOCK_BODY - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy1: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .f' - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy2: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - CALL 'public final fun test1 (_context_receiver_0: .Lazy, _context_receiver_1: .Lazy): kotlin.Unit declared in ' type=kotlin.Unit origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy declared in .f.' type=.Lazy origin=null - _context_receiver_1: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - CALL 'public final fun test2 (_context_receiver_0: .Lazy.test2>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : kotlin.CharSequence - $receiver: GET_VAR '$this$with: .Lazy declared in .f.' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy2: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .f' - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy1: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - CALL 'public final fun test1 (_context_receiver_0: .Lazy, _context_receiver_1: .Lazy): kotlin.Unit declared in ' type=kotlin.Unit origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - _context_receiver_1: GET_VAR '$this$with: .Lazy declared in .f.' type=.Lazy origin=null - CALL 'public final fun test2 (_context_receiver_0: .Lazy.test2>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : kotlin.Int - $receiver: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy.f> - : kotlin.Unit - receiver: GET_VAR 'lazyT: .Lazy.f> declared in .f' type=.Lazy.f> origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy.f>, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy.f>) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy.f> - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .f' - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy1: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - CALL 'public final fun test2 (_context_receiver_0: .Lazy.test2>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : kotlin.Int - $receiver: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy<.Lazy.f>> - : kotlin.Unit - receiver: GET_VAR 'lazyLazyT: .Lazy<.Lazy.f>> declared in .f' type=.Lazy<.Lazy.f>> origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy<.Lazy.f>>, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy<.Lazy.f>>) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy<.Lazy.f>> - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .f' - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy1: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - CALL 'public final fun test2 (_context_receiver_0: .Lazy.test2>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : kotlin.Int - $receiver: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - CALL 'public final fun test3 (_context_receiver_0: .Lazy<.Lazy.test3>>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : T of .f - $receiver: GET_VAR '$this$with: .Lazy declared in .f..' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy<.Lazy.f>> declared in .f.' type=.Lazy<.Lazy.f>> origin=null - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy - : kotlin.Unit - receiver: GET_VAR 'lazy1: .Lazy declared in .f' type=.Lazy origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy - BLOCK_BODY - RETURN type=kotlin.Nothing from='local final fun (): kotlin.Unit declared in .f' - CALL 'public final fun with (receiver: T of kotlin.StandardKt.with, block: @[ExtensionFunctionType] kotlin.Function1): R of kotlin.StandardKt.with [inline] declared in kotlin.StandardKt' type=kotlin.Unit origin=null - : .Lazy<.Lazy.f>> - : kotlin.Unit - receiver: GET_VAR 'lazyLazyT: .Lazy<.Lazy.f>> declared in .f' type=.Lazy<.Lazy.f>> origin=null - block: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1<.Lazy<.Lazy.f>>, kotlin.Unit> origin=LAMBDA - FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL <> ($receiver:.Lazy<.Lazy.f>>) returnType:kotlin.Unit - $receiver: VALUE_PARAMETER name:$this$with type:.Lazy<.Lazy.f>> - BLOCK_BODY - CALL 'public final fun test2 (_context_receiver_0: .Lazy.test2>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : .Lazy.f> - $receiver: GET_VAR '$this$with: .Lazy declared in .f.' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy<.Lazy.f>> declared in .f..' type=.Lazy<.Lazy.f>> origin=null - CALL 'public final fun test3 (_context_receiver_0: .Lazy<.Lazy.test3>>): kotlin.Unit declared in ' type=kotlin.Unit origin=null - : T of .f - $receiver: GET_VAR '$this$with: .Lazy declared in .f.' type=.Lazy origin=null - _context_receiver_0: GET_VAR '$this$with: .Lazy<.Lazy.f>> declared in .f..' type=.Lazy<.Lazy.f>> origin=null diff --git a/compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.kt.txt b/compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.kt.txt deleted file mode 100644 index ded18a94501..00000000000 --- a/compiler/testData/ir/irText/declarations/contextReceivers/lazy.fir.kt.txt +++ /dev/null @@ -1,54 +0,0 @@ -interface Lazy { - -} - -fun test1(_context_receiver_0: Lazy, _context_receiver_1: Lazy) { -} - -fun Lazy.test2(_context_receiver_0: Lazy) { -} - -fun Lazy.test3(_context_receiver_0: Lazy>) { -} - -fun f(lazy1: Lazy, lazy2: Lazy, lazyT: Lazy, lazyLazyT: Lazy>) { - with, Unit>(receiver = lazy1, block = local fun Lazy.() { - return with, Unit>(receiver = lazy2, block = local fun Lazy.() { - test1(_context_receiver_0 = $this$with, _context_receiver_1 = $this$with) - $this$with.test2(_context_receiver_0 = $this$with) - } -) - } -) - with, Unit>(receiver = lazy2, block = local fun Lazy.() { - return with, Unit>(receiver = lazy1, block = local fun Lazy.() { - test1(_context_receiver_0 = $this$with, _context_receiver_1 = $this$with) - $this$with.test2(_context_receiver_0 = $this$with) - } -) - } -) - with, Unit>(receiver = lazyT, block = local fun Lazy.() { - return with, Unit>(receiver = lazy1, block = local fun Lazy.() { - $this$with.test2(_context_receiver_0 = $this$with) - } -) - } -) - with>, Unit>(receiver = lazyLazyT, block = local fun Lazy>.() { - return with, Unit>(receiver = lazy1, block = local fun Lazy.() { - $this$with.test2(_context_receiver_0 = $this$with) - $this$with.test3(_context_receiver_0 = $this$with) - } -) - } -) - with, Unit>(receiver = lazy1, block = local fun Lazy.() { - return with>, Unit>(receiver = lazyLazyT, block = local fun Lazy>.() { - $this$with.test2>(_context_receiver_0 = $this$with) - $this$with.test3(_context_receiver_0 = $this$with) - } -) - } -) -} diff --git a/compiler/testData/ir/irText/declarations/contextReceivers/lazy.kt b/compiler/testData/ir/irText/declarations/contextReceivers/lazy.kt index a82d4eeeea1..2e92fc8310f 100644 --- a/compiler/testData/ir/irText/declarations/contextReceivers/lazy.kt +++ b/compiler/testData/ir/irText/declarations/contextReceivers/lazy.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !LANGUAGE: +ContextReceivers interface Lazy