diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt index 5e6fcd149c0..6194e9792ac 100644 --- a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrVisitor.kt @@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression -import org.jetbrains.kotlin.fir.expressions.impl.FirWhenSubjectExpression import org.jetbrains.kotlin.fir.references.FirPropertyFromParameterCallableReference import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.buildUseSiteScope @@ -798,12 +797,6 @@ internal class Fir2IrVisitor( private fun FirExpression.toIrExpression(): IrExpression { return when (this) { is FirBlock -> convertToIrExpressionOrBlock() - is FirWhenSubjectExpression -> { - val lastSubjectVariable = subjectVariableStack.last() - convertWithOffsets { startOffset, endOffset -> - IrGetValueImpl(startOffset, endOffset, lastSubjectVariable.type, lastSubjectVariable.symbol) - } - } is FirUnitExpression -> convertWithOffsets { startOffset, endOffset -> IrGetObjectValueImpl( startOffset, endOffset, unitType, @@ -917,6 +910,13 @@ internal class Fir2IrVisitor( } } + override fun visitWhenSubjectExpression(whenSubjectExpression: FirWhenSubjectExpression, data: Any?): IrElement { + val lastSubjectVariable = subjectVariableStack.last() + return whenSubjectExpression.convertWithOffsets { startOffset, endOffset -> + IrGetValueImpl(startOffset, endOffset, lastSubjectVariable.type, lastSubjectVariable.symbol) + } + } + private val loopMap = mutableMapOf() override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: Any?): IrElement { diff --git a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt index d2e2305b47e..ef4955b177d 100644 --- a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt +++ b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/ConversionUtils.kt @@ -10,6 +10,7 @@ import com.intellij.psi.tree.IElementType import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.fir.FirReference import org.jetbrains.kotlin.fir.FirSession +import org.jetbrains.kotlin.fir.FirWhenSubject import org.jetbrains.kotlin.fir.declarations.impl.FirVariableImpl import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.* @@ -179,10 +180,12 @@ internal fun FirExpression.generateNotNullOrOther( ): FirWhenExpression { val subjectName = Name.special("<$caseId>") val subjectVariable = generateTemporaryVariable(session, psi, subjectName, this) - val subjectExpression = FirWhenSubjectExpression(session, psi) + val subject = FirWhenSubject() + val subjectExpression = FirWhenSubjectExpressionImpl(session, psi, subject) return FirWhenExpressionImpl( session, basePsi, this, subjectVariable ).apply { + subject.bind(this) branches += FirWhenBranchImpl( session, psi, FirOperatorCallImpl(session, psi, FirOperation.EQ).apply { @@ -219,10 +222,11 @@ internal fun FirExpression.generateLazyLogicalOperation( internal fun KtWhenCondition.toFirWhenCondition( session: FirSession, + subject: FirWhenSubject, convert: KtExpression?.(String) -> FirExpression, toFirOrErrorTypeRef: KtTypeReference?.() -> FirTypeRef ): FirExpression { - val firSubjectExpression = FirWhenSubjectExpression(session, this) + val firSubjectExpression = FirWhenSubjectExpressionImpl(session, this, subject) return when (this) { is KtWhenConditionWithExpression -> { FirOperatorCallImpl( @@ -255,12 +259,13 @@ internal fun KtWhenCondition.toFirWhenCondition( internal fun Array.toFirWhenCondition( session: FirSession, basePsi: KtElement, + subject: FirWhenSubject, convert: KtExpression?.(String) -> FirExpression, toFirOrErrorTypeRef: KtTypeReference?.() -> FirTypeRef ): FirExpression { var firCondition: FirExpression? = null for (condition in this) { - val firConditionElement = condition.toFirWhenCondition(session, convert, toFirOrErrorTypeRef) + val firConditionElement = condition.toFirWhenCondition(session, subject, convert, toFirOrErrorTypeRef) firCondition = when (firCondition) { null -> firConditionElement else -> firCondition.generateLazyLogicalOperation( diff --git a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 282e194e96d..d926135fa8a 100644 --- a/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -972,26 +972,30 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) { } override fun visitWhenExpression(expression: KtWhenExpression, data: Unit): FirElement { - val subjectExpression = expression.subjectExpression - val subject = when (subjectExpression) { - is KtVariableDeclaration -> subjectExpression.initializer - else -> subjectExpression - }?.toFirExpression("Incorrect when subject expression: ${subjectExpression?.text}") - val subjectVariable = when (subjectExpression) { + val ktSubjectExpression = expression.subjectExpression + val subjectExpression = when (ktSubjectExpression) { + is KtVariableDeclaration -> ktSubjectExpression.initializer + else -> ktSubjectExpression + }?.toFirExpression("Incorrect when subject expression: ${ktSubjectExpression?.text}") + val subjectVariable = when (ktSubjectExpression) { is KtVariableDeclaration -> FirVariableImpl( - session, subjectExpression, subjectExpression.nameAsSafeName, - subjectExpression.typeReference.toFirOrImplicitType(), - isVar = false, initializer = subject + session, ktSubjectExpression, ktSubjectExpression.nameAsSafeName, + ktSubjectExpression.typeReference.toFirOrImplicitType(), + isVar = false, initializer = subjectExpression ) else -> null } - val hasSubject = subject != null + val hasSubject = subjectExpression != null + val subject = FirWhenSubject() return FirWhenExpressionImpl( session, expression, - subject, + subjectExpression, subjectVariable ).apply { + if (hasSubject) { + subject.bind(this) + } for (entry in expression.entries) { val branch = entry.expression.toFirBlock() branches += if (!entry.isElse) { @@ -999,6 +1003,7 @@ class RawFirBuilder(val session: FirSession, val stubMode: Boolean) { val firCondition = entry.conditions.toFirWhenCondition( this@RawFirBuilder.session, entry, + subject, { toFirExpression(it) }, { toFirOrErrorType() } ) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt index 8cd48fca79f..84e8c21942b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirBodyResolveTransformer.kt @@ -425,6 +425,18 @@ open class FirBodyResolveTransformer(val session: FirSession, val implicitTypeOn return whenExpression.compose() } + override fun transformWhenSubjectExpression( + whenSubjectExpression: FirWhenSubjectExpression, + data: Any? + ): CompositeTransformResult { + val parentWhen = whenSubjectExpression.whenSubject.whenExpression + val subjectType = parentWhen.subject?.resultType ?: parentWhen.subjectVariable?.returnTypeRef + if (subjectType != null) { + whenSubjectExpression.resultType = subjectType + } + return whenSubjectExpression.compose() + } + override fun transformConstExpression(constExpression: FirConstExpression, data: Any?): CompositeTransformResult { val expectedType = data as FirTypeRef? diff --git a/compiler/fir/resolve/testData/loadCompiledKotlin/coroutines/Basic.txt b/compiler/fir/resolve/testData/loadCompiledKotlin/coroutines/Basic.txt index 67327e4b246..eb6291f6e79 100644 --- a/compiler/fir/resolve/testData/loadCompiledKotlin/coroutines/Basic.txt +++ b/compiler/fir/resolve/testData/loadCompiledKotlin/coroutines/Basic.txt @@ -1,4 +1,4 @@ -public final fun builder(c: R|error: createSuspendFunctionType not supported|): R|kotlin/Unit| +public final fun builder(c: R|class error: createSuspendFunctionType not supported|): R|kotlin/Unit| public final class Controller : R|kotlin/Any| { public final suspend fun suspendFun(): R|kotlin/Unit| diff --git a/compiler/fir/resolve/testData/loadCompiledKotlin/type/SuspendFunction.txt b/compiler/fir/resolve/testData/loadCompiledKotlin/type/SuspendFunction.txt index a7d3f85121d..e3e80e9170f 100644 --- a/compiler/fir/resolve/testData/loadCompiledKotlin/type/SuspendFunction.txt +++ b/compiler/fir/resolve/testData/loadCompiledKotlin/type/SuspendFunction.txt @@ -1,7 +1,8 @@ -public final fun test1(): R|error: createSuspendFunctionType not supported| +public final fun test1(): R|class error: createSuspendFunctionType not supported| -public final fun test2(): R|error: createSuspendFunctionType not supported| +public final fun test2(): R|class error: createSuspendFunctionType not supported| -public final fun test3(): R|kotlin/collections/List| +public final fun test3(): R|kotlin/collections/List| + +public final fun test4(): R|class error: createSuspendFunctionType not supported| -public final fun test4(): R|error: createSuspendFunctionType not supported| diff --git a/compiler/fir/resolve/testData/resolve/expresssions/when.kt b/compiler/fir/resolve/testData/resolve/expresssions/when.kt index 06e1c6cf959..38f66b94736 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/when.kt +++ b/compiler/fir/resolve/testData/resolve/expresssions/when.kt @@ -1 +1,6 @@ -fun foo() = if (true) 1 else 0 \ No newline at end of file +fun foo() = if (true) 1 else 0 + +fun bar(arg: Any?) = when (arg) { + is Int -> arg as Int + else -> 42 +} \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/expresssions/when.txt b/compiler/fir/resolve/testData/resolve/expresssions/when.txt index b748e6e7c5c..7c09d383462 100644 --- a/compiler/fir/resolve/testData/resolve/expresssions/when.txt +++ b/compiler/fir/resolve/testData/resolve/expresssions/when.txt @@ -10,3 +10,14 @@ FILE: when.kt } } + public final fun bar(arg: R|kotlin/Any|?): R|kotlin/Int| { + ^bar when (R|/arg|) { + ($subj$ is R|kotlin/Int|) -> { + (R|/arg| as R|kotlin/Int|) + } + else -> { + Int(42) + } + } + + } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index e5655a40726..1eef6487654 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionStub import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression -import org.jetbrains.kotlin.fir.expressions.impl.FirWhenSubjectExpression import org.jetbrains.kotlin.fir.symbols.ConeCallableSymbol import org.jetbrains.kotlin.fir.symbols.ConeClassLikeSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol @@ -38,7 +37,6 @@ fun ConeKotlinType.render(): String { return when (this) { is ConeTypeVariableType -> "TypeVariable(${this.lookupTag.name})" is ConeDefinitelyNotNullType -> "${original.render()}!" - is ConeKotlinErrorType -> "error: $reason" is ConeClassErrorType -> "class error: $reason" is ConeCapturedType -> "captured type: lowerType = ${lowerType?.render()}" is ConeClassLikeType -> { @@ -540,6 +538,10 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() { println("}") } + override fun visitWhenSubjectExpression(whenSubjectExpression: FirWhenSubjectExpression) { + print("\$subj\$") + } + override fun visitTryExpression(tryExpression: FirTryExpression) { tryExpression.annotations.renderAnnotations() print("try") @@ -604,7 +606,6 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() { when (expression) { is FirExpressionStub -> "STUB" is FirUnitExpression -> "Unit" - is FirWhenSubjectExpression -> "\$subj\$" is FirElseIfTrueCondition -> "else" else -> "??? ${expression.javaClass}" } diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirWhenSubject.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirWhenSubject.kt new file mode 100644 index 00000000000..616752ae706 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirWhenSubject.kt @@ -0,0 +1,16 @@ +/* + * 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 + +import org.jetbrains.kotlin.fir.expressions.FirWhenExpression + +class FirWhenSubject { + lateinit var whenExpression: FirWhenExpression + + fun bind(expression: FirWhenExpression) { + whenExpression = expression + } +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirWhenSubjectExpression.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirWhenSubjectExpression.kt new file mode 100644 index 00000000000..c7d0ee11302 --- /dev/null +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/FirWhenSubjectExpression.kt @@ -0,0 +1,16 @@ +/* + * 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.expressions + +import org.jetbrains.kotlin.fir.FirWhenSubject +import org.jetbrains.kotlin.fir.visitors.FirVisitor + +interface FirWhenSubjectExpression : FirExpression { + val whenSubject: FirWhenSubject + + override fun accept(visitor: FirVisitor, data: D): R = + visitor.visitWhenSubjectExpression(this, data) +} \ No newline at end of file diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpression.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionImpl.kt similarity index 56% rename from compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpression.kt rename to compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionImpl.kt index 240a0eb04f4..88030724b4a 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpression.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/expressions/impl/FirWhenSubjectExpressionImpl.kt @@ -6,11 +6,12 @@ package org.jetbrains.kotlin.fir.expressions.impl import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.fir.FirAbstractElement import org.jetbrains.kotlin.fir.FirSession -import org.jetbrains.kotlin.fir.expressions.FirExpression +import org.jetbrains.kotlin.fir.FirWhenSubject +import org.jetbrains.kotlin.fir.expressions.FirWhenSubjectExpression -class FirWhenSubjectExpression( +class FirWhenSubjectExpressionImpl( session: FirSession, - psi: PsiElement? -): FirAbstractExpression(session, psi) \ No newline at end of file + psi: PsiElement?, + override val whenSubject: FirWhenSubject +) : FirAbstractExpression(session, psi), FirWhenSubjectExpression \ No newline at end of file diff --git a/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirTransformerGenerated.kt b/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirTransformerGenerated.kt index d2e25ae502f..466711cfbbc 100644 --- a/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirTransformerGenerated.kt +++ b/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirTransformerGenerated.kt @@ -276,6 +276,10 @@ abstract class FirTransformer : FirVisitor { + return transformExpression(whenSubjectExpression, data) + } + open fun transformWrappedArgumentExpression(wrappedArgumentExpression: FirWrappedArgumentExpression, data: D): CompositeTransformResult { return transformExpression(wrappedArgumentExpression, data) } @@ -752,6 +756,10 @@ abstract class FirTransformer : FirVisitor { + return transformWhenSubjectExpression(whenSubjectExpression, data) + } + final override fun visitWhileLoop(whileLoop: FirWhileLoop, data: D): CompositeTransformResult { return transformWhileLoop(whileLoop, data) } diff --git a/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorGenerated.kt b/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorGenerated.kt index bdc28abd30b..f8986a7dae1 100644 --- a/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorGenerated.kt +++ b/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorGenerated.kt @@ -276,6 +276,10 @@ abstract class FirVisitor { return visitExpression(whenExpression, data) } + open fun visitWhenSubjectExpression(whenSubjectExpression: FirWhenSubjectExpression, data: D): R { + return visitExpression(whenSubjectExpression, data) + } + open fun visitWrappedArgumentExpression(wrappedArgumentExpression: FirWrappedArgumentExpression, data: D): R { return visitExpression(wrappedArgumentExpression, data) } diff --git a/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorVoidGenerated.kt b/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorVoidGenerated.kt index 0e4ed27de1b..f7f1616e1b5 100644 --- a/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorVoidGenerated.kt +++ b/compiler/fir/tree/visitors/org/jetbrains/kotlin/fir/visitors/FirVisitorVoidGenerated.kt @@ -276,6 +276,10 @@ abstract class FirVisitorVoid : FirVisitor() { visitExpression(whenExpression, null) } + open fun visitWhenSubjectExpression(whenSubjectExpression: FirWhenSubjectExpression) { + visitExpression(whenSubjectExpression, null) + } + open fun visitWrappedArgumentExpression(wrappedArgumentExpression: FirWrappedArgumentExpression) { visitExpression(wrappedArgumentExpression, null) } @@ -752,6 +756,10 @@ abstract class FirVisitorVoid : FirVisitor() { visitWhenExpression(whenExpression) } + final override fun visitWhenSubjectExpression(whenSubjectExpression: FirWhenSubjectExpression, data: Nothing?) { + visitWhenSubjectExpression(whenSubjectExpression) + } + final override fun visitWhileLoop(whileLoop: FirWhileLoop, data: Nothing?) { visitWhileLoop(whileLoop) }