FIR2IR: refactor implicit cast insertion, part 1: implicit cast

This commit is contained in:
Jinseong Jeon
2020-10-23 11:50:03 -07:00
committed by teamcityserver
parent e9a7b64ca0
commit 8f8ee88957
2 changed files with 131 additions and 85 deletions
@@ -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<IrElement, IrElement>() {
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
)
}
}
@@ -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 <T : IrDeclaration> 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()
)