From 8f8ee88957e13aa51a53bdd61d8dd7f6c039017e Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Fri, 23 Oct 2020 11:50:03 -0700 Subject: [PATCH] FIR2IR: refactor implicit cast insertion, part 1: implicit cast --- .../fir/backend/Fir2IrImplicitCastInserter.kt | 126 ++++++++++++++++++ .../kotlin/fir/backend/Fir2IrVisitor.kt | 90 +------------ 2 files changed, 131 insertions(+), 85 deletions(-) create mode 100644 compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt diff --git a/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt new file mode 100644 index 00000000000..2653c51633c --- /dev/null +++ b/compiler/fir/fir2ir/src/org/jetbrains/kotlin/fir/backend/Fir2IrImplicitCastInserter.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.backend + +import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast +import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression +import org.jetbrains.kotlin.fir.references.FirReference +import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference +import org.jetbrains.kotlin.fir.render +import org.jetbrains.kotlin.fir.resolve.scope +import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator +import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirAnonymousFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol +import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol +import org.jetbrains.kotlin.fir.types.ConeIntersectionType +import org.jetbrains.kotlin.fir.types.ConeKotlinType +import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef +import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.IrTypeOperator +import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.name.Name + +class Fir2IrImplicitCastInserter( + private val components: Fir2IrComponents, + private val visitor: Fir2IrVisitor +) : Fir2IrComponents by components, FirDefaultVisitor() { + + private fun FirTypeRef.toIrType(): IrType = with(typeConverter) { toIrType() } + + private fun ConeKotlinType.toIrType(): IrType = with(typeConverter) { toIrType() } + + override fun visitElement(element: FirElement, data: IrElement): IrElement { + TODO("Should not be here: ${element.render()}") + } + + override fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast, data: IrElement): IrExpression { + return implicitCastOrExpression(data as IrExpression, expressionWithSmartcast.typeRef) + } + + internal fun convertToImplicitCastExpression( + expressionWithSmartcast: FirExpressionWithSmartcast, calleeReference: FirReference + ): IrExpression { + val originalExpression = expressionWithSmartcast.originalExpression + val value = visitor.convertToIrExpression(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) { + val unwrappedSymbol = (referencedSymbol as? FirCallableSymbol)?.overriddenSymbol ?: referencedSymbol + castType.intersectedTypes.forEach { + if (it.doesContainReferencedSymbolInScope(unwrappedSymbol, calleeReference.name)) { + return implicitCastOrExpression(value, it) + } + } + } + } + return if (originalExpression is FirThisReceiverExpression && + originalExpression.calleeReference.boundSymbol is FirAnonymousFunctionSymbol + ) { + // If the original is a "this" in a local function and original.type is the same as castType, + // we still want to keep the cast. See kt-42517 + implicitCast(value, castTypeRef.toIrType()) + } else { + implicitCastOrExpression(value, castTypeRef.toIrType()) + } + } + + private fun ConeKotlinType.doesContainReferencedSymbolInScope( + referencedSymbol: AbstractFirBasedSymbol<*>, name: Name + ): Boolean { + val scope = scope(session, components.scopeSession, FakeOverrideTypeCalculator.Forced) ?: 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 implicitCastOrExpression(original: IrExpression, castType: ConeKotlinType): IrExpression { + return implicitCastOrExpression(original, castType.toIrType()) + } + + private fun implicitCastOrExpression(original: IrExpression, castType: FirTypeRef): IrExpression { + return implicitCastOrExpression(original, castType.toIrType()) + } + + internal fun implicitCastOrExpression(original: IrExpression, castType: IrType): IrExpression { + return original.takeIf { it.type == castType } ?: implicitCast(original, castType) + } + + private fun implicitCast(original: IrExpression, castType: IrType): IrExpression { + return IrTypeOperatorCallImpl( + original.startOffset, + original.endOffset, + castType, + IrTypeOperator.IMPLICIT_CAST, + castType, + original + ) + } +} 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 862a9cee7f5..0fa4fdfc3e3 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 @@ -23,10 +23,7 @@ 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.isIteratorNext -import org.jetbrains.kotlin.fir.resolve.scope import org.jetbrains.kotlin.fir.resolve.toSymbol -import org.jetbrains.kotlin.fir.scopes.FakeOverrideTypeCalculator -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 @@ -57,14 +54,14 @@ class Fir2IrVisitor( private val annotationGenerator = AnnotationGenerator(this) + private val implicitCastInserter = Fir2IrImplicitCastInserter(components, this) + private val memberGenerator = ClassMemberGenerator(components, this, conversionScope) private val operatorGenerator = OperatorExpressionGenerator(components, this, conversionScope) 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 { @@ -419,87 +416,10 @@ class Fir2IrVisitor( return visitQualifiedAccessExpression(thisReceiverExpression, data) } - 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 implicitCastOrExpression(original: IrExpression, castType: IrType): IrExpression { - return original.takeIf { it.type == castType } ?: implicitCast(original, castType) - } - - private fun implicitCast(original: IrExpression, castType: IrType): IrExpression { - return IrTypeOperatorCallImpl( - original.startOffset, - original.endOffset, - castType, - IrTypeOperator.IMPLICIT_CAST, - castType, - original - ) - } - - private fun ConeKotlinType.doesContainReferencedSymbolInScope( - referencedSymbol: AbstractFirBasedSymbol<*>, name: Name - ): Boolean { - val scope = scope(session, components.scopeSession, FakeOverrideTypeCalculator.Forced) ?: 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 originalExpression = expressionWithSmartcast.originalExpression - val value = convertToIrExpression(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) { - val unwrappedSymbol = (referencedSymbol as? FirCallableSymbol)?.overriddenSymbol ?: referencedSymbol - castType.intersectedTypes.forEach { - if (it.doesContainReferencedSymbolInScope(unwrappedSymbol, calleeReference.name)) { - return implicitCastOrExpression(value, it) - } - } - } - } - return if (originalExpression is FirThisReceiverExpression && - originalExpression.calleeReference.boundSymbol is FirAnonymousFunctionSymbol - ) { - // If the original is a "this" in a local function and original.type is the same as castType, - // we still want to keep the cast. See kt-42517 - implicitCast(value, castTypeRef.toIrType()) - } else { - 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) + return implicitCastInserter.visitExpressionWithSmartcast(expressionWithSmartcast, value) } override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess, data: Any?): IrElement { @@ -583,7 +503,7 @@ class Fir2IrVisitor( return when (expression) { null -> null is FirResolvedQualifier -> callGenerator.convertToGetObject(expression, callableReferenceAccess) - is FirExpressionWithSmartcast -> convertToImplicitCastExpression(expression, calleeReference) + is FirExpressionWithSmartcast -> implicitCastInserter.convertToImplicitCastExpression(expression, calleeReference) is FirFunctionCall, is FirThisReceiverExpression, is FirCallableReferenceAccess -> convertToIrExpression(expression) else -> if (expression is FirQualifiedAccessExpression && expression.explicitReceiver == null) { val variableAsFunctionMode = calleeReference is FirResolvedNamedReference && @@ -735,7 +655,7 @@ class Fir2IrVisitor( if (notNullType == originalType) { irGetLhsValue() } else { - implicitCastOrExpression( + implicitCastInserter.implicitCastOrExpression( irGetLhsValue(), firLhsVariable.returnTypeRef.resolvedTypeFromPrototype(notNullType).toIrType() )