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 3f21bc7d6cd..61fdd57cb6b 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 @@ -18,15 +18,16 @@ import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition import org.jetbrains.kotlin.fir.expressions.impl.FirStubStatement import org.jetbrains.kotlin.fir.expressions.impl.FirUnitExpression +import org.jetbrains.kotlin.fir.references.FirReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.resolve.isIteratorNext +import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.transformers.IntegerLiteralTypeApproximationTransformer import org.jetbrains.kotlin.fir.scopes.impl.FirIntegerOperator -import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol -import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol -import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.* +import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.transformSingle import org.jetbrains.kotlin.ir.IrElement @@ -46,6 +47,7 @@ import org.jetbrains.kotlin.ir.types.makeNullable import org.jetbrains.kotlin.ir.util.constructors import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtForExpression @@ -67,6 +69,8 @@ class Fir2IrVisitor( private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() } + private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() } + private fun applyParentFromStackTo(declaration: T): T = conversionScope.applyParentFromStackTo(declaration) override fun visitElement(element: FirElement, data: Any?): IrElement { @@ -266,7 +270,9 @@ class Fir2IrVisitor( } else { functionCall } - val explicitReceiverExpression = convertToIrReceiverExpression(functionCall.explicitReceiver) + val explicitReceiverExpression = convertToIrReceiverExpression( + functionCall.explicitReceiver, functionCall.calleeReference + ) return callGenerator.convertToIrCall(convertibleCall, convertibleCall.typeRef, explicitReceiverExpression) } @@ -280,7 +286,9 @@ class Fir2IrVisitor( } override fun visitQualifiedAccessExpression(qualifiedAccessExpression: FirQualifiedAccessExpression, data: Any?): IrElement { - val explicitReceiverExpression = convertToIrReceiverExpression(qualifiedAccessExpression.explicitReceiver) + val explicitReceiverExpression = convertToIrReceiverExpression( + qualifiedAccessExpression.explicitReceiver, qualifiedAccessExpression.calleeReference + ) return callGenerator.convertToIrCall(qualifiedAccessExpression, qualifiedAccessExpression.typeRef, explicitReceiverExpression) } @@ -318,30 +326,87 @@ class Fir2IrVisitor( return visitQualifiedAccessExpression(thisReceiverExpression, data) } - override fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast, data: Any?): IrElement { - // Generate the expression with the original type and then cast it to the smart cast type. - val value = convertToIrExpression(expressionWithSmartcast.originalExpression) - val castType = expressionWithSmartcast.typeRef.toIrType() - if (value.type == castType) return value + private fun implicitCastOrExpression(original: IrExpression, castType: IrType): IrExpression { + if (original.type == castType) return original return IrTypeOperatorCallImpl( - value.startOffset, - value.endOffset, + original.startOffset, + original.endOffset, castType, IrTypeOperator.IMPLICIT_CAST, castType, - value + original ) } + private fun implicitCastOrExpression(original: IrExpression, castType: ConeKotlinType): IrExpression { + return implicitCastOrExpression(original, castType.toIrType()) + } + + private fun implicitCastOrExpression(original: IrExpression, castType: FirTypeRef): IrExpression { + return implicitCastOrExpression(original, castType.toIrType()) + } + + private fun ConeKotlinType.doesContainReferencedSymbolInScope( + referencedSymbol: AbstractFirBasedSymbol<*>, name: Name + ): Boolean { + val scope = scope(session, components.scopeSession) ?: return false + var result = false + val processor = { it: FirCallableSymbol<*> -> + if (!result && it == referencedSymbol) { + result = true + } + } + when (referencedSymbol) { + is FirPropertySymbol -> scope.processPropertiesByName(name, processor) + is FirFunctionSymbol -> scope.processFunctionsByName(name, processor) + } + return result + } + + private fun convertToImplicitCastExpression( + expressionWithSmartcast: FirExpressionWithSmartcast, calleeReference: FirReference + ): IrExpression { + val value = convertToIrExpression(expressionWithSmartcast.originalExpression) + val castTypeRef = expressionWithSmartcast.typeRef + if (calleeReference !is FirResolvedNamedReference) { + return implicitCastOrExpression(value, castTypeRef) + } + val referencedSymbol = calleeReference.resolvedSymbol + if (referencedSymbol !is FirPropertySymbol && referencedSymbol !is FirFunctionSymbol) { + return implicitCastOrExpression(value, castTypeRef) + } + + val originalTypeRef = expressionWithSmartcast.originalType + if (castTypeRef is FirResolvedTypeRef && originalTypeRef is FirResolvedTypeRef) { + val castType = castTypeRef.type + if (castType is ConeIntersectionType) { + castType.intersectedTypes.forEach { + if (it.doesContainReferencedSymbolInScope(referencedSymbol, calleeReference.name)) { + return implicitCastOrExpression(value, it) + } + } + } + } + return implicitCastOrExpression(value, castTypeRef.toIrType()) + } + + override fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast, data: Any?): IrElement { + // Generate the expression with the original type and then cast it to the smart cast type. + val value = convertToIrExpression(expressionWithSmartcast.originalExpression) + return implicitCastOrExpression(value, expressionWithSmartcast.typeRef) + } + override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { val explicitReceiverExpression = convertToIrReceiverExpression( - callableReferenceAccess.explicitReceiver, callableReferenceMode = true + callableReferenceAccess.explicitReceiver, callableReferenceAccess.calleeReference, callableReferenceMode = true ) return callGenerator.convertToIrCallableReference(callableReferenceAccess, explicitReceiverExpression) } override fun visitVariableAssignment(variableAssignment: FirVariableAssignment, data: Any?): IrElement { - val explicitReceiverExpression = convertToIrReceiverExpression(variableAssignment.explicitReceiver) + val explicitReceiverExpression = convertToIrReceiverExpression( + variableAssignment.explicitReceiver, variableAssignment.calleeReference + ) return callGenerator.convertToIrSetCall(variableAssignment, explicitReceiverExpression) } @@ -371,10 +436,15 @@ class Fir2IrVisitor( } } - private fun convertToIrReceiverExpression(expression: FirExpression?, callableReferenceMode: Boolean = false): IrExpression? { + private fun convertToIrReceiverExpression( + expression: FirExpression?, + calleeReference: FirReference, + callableReferenceMode: Boolean = false + ): IrExpression? { return when (expression) { null -> null is FirResolvedQualifier -> callGenerator.convertToGetObject(expression, callableReferenceMode) + is FirExpressionWithSmartcast -> convertToImplicitCastExpression(expression, calleeReference) else -> convertToIrExpression(expression) } } diff --git a/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt b/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt index 0f67a5d1a66..509ef35fabd 100644 --- a/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt +++ b/compiler/testData/codegen/box/casts/intersectionTypeSmartcast.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR interface A { fun foo(): Any? } diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/also.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/also.kt index 7b2e9f43993..405456088cd 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/also.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/also.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt index 112e903e66a..7f1a53e82ed 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/inlineWithStateMachine.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt index b290f014307..ef710fdbdc1 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/simple.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailCallIntrinsics.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailCallIntrinsics.kt index 1eec19a8cf3..81bd0db3bec 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailCallIntrinsics.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailCallIntrinsics.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailSuspendUnitFun.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailSuspendUnitFun.kt index 7f6a82e2d70..f40cfb84721 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailSuspendUnitFun.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tailSuspendUnitFun.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatchTailCall.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatchTailCall.kt index c8659887549..da86c7c294b 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatchTailCall.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/tryCatchTailCall.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt index 4cde20d7669..555a859bc12 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/unreachable.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt index f77ace1e0cb..39babe0511e 100644 --- a/compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt +++ b/compiler/testData/codegen/box/coroutines/tailCallOptimizations/whenUnit.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // TARGET_BACKEND: JVM // FULL_JDK // WITH_RUNTIME diff --git a/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt b/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt index 38f836f9f20..b2fd2b389c6 100644 --- a/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt +++ b/compiler/testData/codegen/box/when/enumOptimization/kt14802.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND_FIR: JVM_IR // CHECK_CASES_COUNT: function=crash count=2 // CHECK_IF_COUNT: function=crash count=1 diff --git a/compiler/testData/ir/irText/declarations/localDelegatedProperties.fir.txt b/compiler/testData/ir/irText/declarations/localDelegatedProperties.fir.txt index a48503ef25e..96a640698ca 100644 --- a/compiler/testData/ir/irText/declarations/localDelegatedProperties.fir.txt +++ b/compiler/testData/ir/irText/declarations/localDelegatedProperties.fir.txt @@ -14,8 +14,7 @@ FILE fqName: fileName:/localDelegatedProperties.kt GET_VAR 'var x: IrErrorType [var] declared in .test2' type=IrErrorType origin=null SET_VAR 'var x: IrErrorType [var] declared in .test2' type=kotlin.Unit origin=EQ CALL 'public final fun inc (): kotlin.Int [operator] declared in kotlin.Int' type=kotlin.Int origin=null - $this: TYPE_OP type=IrErrorType origin=IMPLICIT_CAST typeOperand=IrErrorType - GET_VAR 'val tmp_0: kotlin.Int [val] declared in .test2' type=kotlin.Int origin=null + $this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in .test2' type=kotlin.Int origin=null TYPE_OP type=IrErrorType origin=IMPLICIT_CAST typeOperand=IrErrorType GET_VAR 'val tmp_0: kotlin.Int [val] declared in .test2' type=kotlin.Int origin=null SET_VAR 'var x: IrErrorType [var] declared in .test2' type=kotlin.Unit origin=EQ