FIR: introduce FirExpressionWithSmartcastToNull

This new kind of expression encompasses the nullability of the original
expression after null check (or equivalent `is Nothing?` check).

Unlike FirExpressionWithSmartcast, this expression won't be materialized
during conversion to backend IR. Also, Nothing? is discarded when
computing the intersection of possible types from smartcast info.
In that way, Nothing? is not used during resolution, while such
smartcast info is stored in it (and the expression kind itself).
This commit is contained in:
Jinseong Jeon
2021-04-29 23:50:22 -07:00
committed by TeamCityServer
parent 8da183e4f4
commit 8e10b5fdec
36 changed files with 370 additions and 104 deletions
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2021 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.expressions
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.*
import org.jetbrains.kotlin.fir.FirImplementationDetail
/*
* This file was generated automatically
* DO NOT MODIFY IT MANUALLY
*/
abstract class FirExpressionWithSmartcastToNull : FirExpressionWithSmartcast() {
abstract override val source: FirSourceElement?
abstract override val typeRef: FirTypeRef
abstract override val annotations: List<FirAnnotationCall>
abstract override val calleeReference: FirReference
abstract override val typeArguments: List<FirTypeProjection>
abstract override val explicitReceiver: FirExpression?
abstract override val dispatchReceiver: FirExpression
abstract override val extensionReceiver: FirExpression
abstract override val originalExpression: FirQualifiedAccessExpression
abstract override val typesFromSmartCast: Collection<ConeKotlinType>
abstract override val originalType: FirTypeRef
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitExpressionWithSmartcastToNull(this, data)
@Suppress("UNCHECKED_CAST")
override fun <E: FirElement, D> transform(transformer: FirTransformer<D>, data: D): E =
transformer.transformExpressionWithSmartcastToNull(this, data) as E
@FirImplementationDetail
abstract override fun replaceSource(newSource: FirSourceElement?)
abstract override fun replaceTypeRef(newTypeRef: FirTypeRef)
abstract override fun replaceCalleeReference(newCalleeReference: FirReference)
abstract override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>)
abstract override fun replaceExplicitReceiver(newExplicitReceiver: FirExpression?)
abstract override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull
abstract override fun <D> transformCalleeReference(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull
abstract override fun <D> transformTypeArguments(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull
abstract override fun <D> transformExplicitReceiver(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull
abstract override fun <D> transformDispatchReceiver(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull
abstract override fun <D> transformExtensionReceiver(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull
}
@@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.expressions.FirComponentCall
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
@@ -480,6 +481,10 @@ abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {
return transformElement(expressionWithSmartcast, data)
}
open fun transformExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: D): FirStatement {
return transformElement(expressionWithSmartcastToNull, data)
}
open fun transformSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: D): FirStatement {
return transformElement(safeCallExpression, data)
}
@@ -980,6 +985,10 @@ abstract class FirTransformer<in D> : FirVisitor<FirElement, D>() {
return transformExpressionWithSmartcast(expressionWithSmartcast, data)
}
final override fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: D): FirStatement {
return transformExpressionWithSmartcastToNull(expressionWithSmartcastToNull, data)
}
final override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: D): FirStatement {
return transformSafeCallExpression(safeCallExpression, data)
}
@@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.expressions.FirComponentCall
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
@@ -309,6 +310,8 @@ abstract class FirVisitor<out R, in D> {
open fun visitExpressionWithSmartcast(expressionWithSmartcast: FirExpressionWithSmartcast, data: D): R = visitElement(expressionWithSmartcast, data)
open fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: D): R = visitElement(expressionWithSmartcastToNull, data)
open fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: D): R = visitElement(safeCallExpression, data)
open fun visitCheckedSafeCallSubject(checkedSafeCallSubject: FirCheckedSafeCallSubject, data: D): R = visitElement(checkedSafeCallSubject, data)
@@ -91,6 +91,7 @@ import org.jetbrains.kotlin.fir.expressions.FirComponentCall
import org.jetbrains.kotlin.fir.expressions.FirCallableReferenceAccess
import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcast
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull
import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression
import org.jetbrains.kotlin.fir.expressions.FirCheckedSafeCallSubject
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
@@ -479,6 +480,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitElement(expressionWithSmartcast)
}
open fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull) {
visitElement(expressionWithSmartcastToNull)
}
open fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression) {
visitElement(safeCallExpression)
}
@@ -979,6 +984,10 @@ abstract class FirVisitorVoid : FirVisitor<Unit, Nothing?>() {
visitExpressionWithSmartcast(expressionWithSmartcast)
}
final override fun visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull: FirExpressionWithSmartcastToNull, data: Nothing?) {
visitExpressionWithSmartcastToNull(expressionWithSmartcastToNull)
}
final override fun visitSafeCallExpression(safeCallExpression: FirSafeCallExpression, data: Nothing?) {
visitSafeCallExpression(safeCallExpression)
}
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2021 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.expressions.builder
import org.jetbrains.kotlin.fir.expressions.FirExpressionWithSmartcastToNull
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirExpressionWithSmartcastToNullImpl
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirTypeRef
class FirExpressionWithSmartcastToNullBuilder {
lateinit var originalExpression: FirQualifiedAccessExpression
lateinit var typeRef: FirTypeRef
lateinit var typesFromSmartCast: Collection<ConeKotlinType>
fun build(): FirExpressionWithSmartcastToNull {
return FirExpressionWithSmartcastToNullImpl(originalExpression, typeRef, typesFromSmartCast)
}
}
inline fun buildExpressionWithSmartcastToNull(init: FirExpressionWithSmartcastToNullBuilder.() -> Unit): FirExpressionWithSmartcastToNull {
return FirExpressionWithSmartcastToNullBuilder().apply(init).build()
}
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2021 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.expressions.impl
import org.jetbrains.kotlin.fir.FirImplementationDetail
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.fir.types.FirTypeProjection
import org.jetbrains.kotlin.fir.types.FirTypeRef
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.FirVisitor
import org.jetbrains.kotlin.fir.visitors.transformSingle
class FirExpressionWithSmartcastToNullImpl(
override var originalExpression: FirQualifiedAccessExpression,
override val typeRef: FirTypeRef,
override val typesFromSmartCast: Collection<ConeKotlinType>
) : FirExpressionWithSmartcastToNull() {
init {
assert(originalExpression.typeRef is FirResolvedTypeRef)
}
override val source: FirSourceElement? get() = originalExpression.source
override val annotations: List<FirAnnotationCall> get() = originalExpression.annotations
override val typeArguments: List<FirTypeProjection> get() = originalExpression.typeArguments
override val explicitReceiver: FirExpression? get() = originalExpression.explicitReceiver
override val dispatchReceiver: FirExpression get() = originalExpression.dispatchReceiver
override val extensionReceiver: FirExpression get() = originalExpression.extensionReceiver
override val calleeReference: FirReference get() = originalExpression.calleeReference
override val originalType: FirTypeRef get() = originalExpression.typeRef
override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
originalExpression = originalExpression.transformSingle(transformer, data)
return this
}
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
originalExpression.accept(visitor, data)
}
override fun <D> transformCalleeReference(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
throw IllegalStateException()
}
override fun <D> transformExplicitReceiver(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
throw IllegalStateException()
}
override fun <D> transformDispatchReceiver(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
throw IllegalStateException()
}
override fun <D> transformExtensionReceiver(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
throw IllegalStateException()
}
override fun <D> transformTypeArguments(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
throw IllegalStateException()
}
override fun <D> transformAnnotations(transformer: FirTransformer<D>, data: D): FirExpressionWithSmartcastToNull {
throw IllegalStateException()
}
override fun replaceTypeArguments(newTypeArguments: List<FirTypeProjection>) {
throw IllegalStateException()
}
override fun replaceCalleeReference(newCalleeReference: FirReference) {
throw IllegalStateException()
}
override fun replaceExplicitReceiver(newExplicitReceiver: FirExpression?) {
throw IllegalStateException()
}
override fun replaceTypeRef(newTypeRef: FirTypeRef) {}
@FirImplementationDetail
override fun replaceSource(newSource: FirSourceElement?) {
}
}
@@ -108,6 +108,7 @@ object FirTreeBuilder : AbstractFirTreeBuilder() {
val callableReferenceAccess = element("CallableReferenceAccess", Expression, qualifiedAccessExpression)
val thisReceiverExpression = element("ThisReceiverExpression", Expression, qualifiedAccessExpression)
val expressionWithSmartcast = element("ExpressionWithSmartcast", Expression, qualifiedAccessExpression)
val expressionWithSmartcastToNull = element("ExpressionWithSmartcastToNull", Expression, expressionWithSmartcast)
val safeCallExpression = element("SafeCallExpression", Expression, expression)
val checkedSafeCallSubject = element("CheckedSafeCallSubject", Expression, expression)
val getClassCall = element("GetClassCall", Expression, expression, call)
@@ -156,6 +156,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(qualifiedAccessExpression)
noImpl(expressionWithSmartcast)
noImpl(expressionWithSmartcastToNull)
impl(getClassCall) {
default("argument") {
@@ -459,6 +459,12 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+field("originalType", typeRef)
}
expressionWithSmartcastToNull.configure {
+field("originalExpression", qualifiedAccessExpression)
+field("typesFromSmartCast", "Collection<ConeKotlinType>", null, customType = coneKotlinTypeType)
+field("originalType", typeRef)
}
safeCallExpression.configure {
+field("receiver", expression).withTransform()
// Special node that might be used as a reference to receiver of a safe call after null check