[FIR2IR] Use intersection type approximation for receivers

This commit is contained in:
Mikhail Glukhikh
2020-05-06 16:53:10 +03:00
parent 292563451c
commit d8f9643650
12 changed files with 88 additions and 29 deletions
@@ -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 <T : IrDeclaration> 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)
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
interface A {
fun foo(): Any?
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// FULL_JDK
// WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_FIR: JVM_IR
// CHECK_CASES_COUNT: function=crash count=2
// CHECK_IF_COUNT: function=crash count=1
@@ -14,8 +14,7 @@ FILE fqName:<root> fileName:/localDelegatedProperties.kt
GET_VAR 'var x: IrErrorType [var] declared in <root>.test2' type=IrErrorType origin=null
SET_VAR 'var x: IrErrorType [var] declared in <root>.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 <root>.test2' type=kotlin.Int origin=null
$this: GET_VAR 'val tmp_0: kotlin.Int [val] declared in <root>.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 <root>.test2' type=kotlin.Int origin=null
SET_VAR 'var x: IrErrorType [var] declared in <root>.test2' type=kotlin.Unit origin=EQ