Support nullable callable references in FIR resolve

This commit is contained in:
Mikhail Glukhikh
2020-01-30 19:22:38 +03:00
parent a584589665
commit aeb6f35571
13 changed files with 34 additions and 20 deletions
@@ -207,7 +207,9 @@ class FirCallResolver(
when { when {
referencedSymbol is FirClassLikeSymbol<*> -> { referencedSymbol is FirClassLikeSymbol<*> -> {
val classId = referencedSymbol.classId val classId = referencedSymbol.classId
return FirResolvedQualifierImpl(nameReference.source, classId.packageFqName, classId.relativeClassName).apply { return FirResolvedQualifierImpl(
nameReference.source, classId.packageFqName, classId.relativeClassName, safe = false
).apply {
typeArguments.addAll(qualifiedAccess.typeArguments) typeArguments.addAll(qualifiedAccess.typeArguments)
resultType = if (classId.isLocal) { resultType = if (classId.isLocal) {
typeForQualifierByDeclaration(referencedSymbol.fir, resultType, session) typeForQualifierByDeclaration(referencedSymbol.fir, resultType, session)
@@ -65,7 +65,8 @@ class FirQualifiedNameResolver(components: BodyResolveComponents) : BodyResolveC
return FirResolvedQualifierImpl( return FirResolvedQualifierImpl(
source, source,
resolved.packageFqName, resolved.packageFqName,
resolved.relativeClassFqName resolved.relativeClassFqName,
safe = false
).apply { resultType = typeForQualifier(this) } ).apply { resultType = typeForQualifier(this) }
} }
@@ -69,7 +69,7 @@ class FirDoubleColonExpressionResolver(
private fun shouldTryResolveLHSAsExpression(expression: FirCallableReferenceAccess): Boolean { private fun shouldTryResolveLHSAsExpression(expression: FirCallableReferenceAccess): Boolean {
val lhs = expression.explicitReceiver ?: return false val lhs = expression.explicitReceiver ?: return false
return lhs.canBeConsideredProperExpression() /* && !expression.hasQuestionMarks */ return lhs.canBeConsideredProperExpression() && !expression.safe
} }
private fun shouldTryResolveLHSAsType(expression: FirCallableReferenceAccess): Boolean { private fun shouldTryResolveLHSAsType(expression: FirCallableReferenceAccess): Boolean {
@@ -168,7 +168,7 @@ class FirDoubleColonExpressionResolver(
else -> ConeStarProjection else -> ConeStarProjection
} }
}, },
isNullable = false // TODO: Use org.jetbrains.kotlin.psi.KtDoubleColonExpression.getHasQuestionMarks isNullable = expression.safe
) )
return DoubleColonLHS.Type(type) return DoubleColonLHS.Type(type)
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.expressions.impl.FirErrorExpressionImpl import org.jetbrains.kotlin.fir.expressions.impl.FirErrorExpressionImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl import org.jetbrains.kotlin.fir.expressions.impl.FirFunctionCallImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedQualifierImpl
import org.jetbrains.kotlin.fir.expressions.impl.FirVariableAssignmentImpl import org.jetbrains.kotlin.fir.expressions.impl.FirVariableAssignmentImpl
import org.jetbrains.kotlin.fir.references.* import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl
@@ -357,8 +358,12 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) :
} }
callableReferenceAccess.annotations.forEach { it.accept(this, data) } callableReferenceAccess.annotations.forEach { it.accept(this, data) }
val transformedLHS = val explicitReceiver = callableReferenceAccess.explicitReceiver
callableReferenceAccess.explicitReceiver?.transformSingle(this, ResolutionMode.ContextIndependent) val transformedLHS = explicitReceiver?.transformSingle(this, ResolutionMode.ContextIndependent)?.apply {
if (this is FirResolvedQualifierImpl && callableReferenceAccess.safe) {
this.safe = true
}
}
val callableReferenceAccessWithTransformedLHS = val callableReferenceAccessWithTransformedLHS =
if (transformedLHS != null) if (transformedLHS != null)
@@ -3,6 +3,6 @@ val Any?.meaning: Int
fun test() { fun test() {
val f = Any?::meaning val f = Any?::meaning
f.<!INAPPLICABLE_CANDIDATE!>get<!>(null) f.get(null)
f.get("") f.get("")
} }
@@ -4,7 +4,7 @@ FILE: getOnKProperty.kt
^ Int(42) ^ Int(42)
} }
public final fun test(): R|kotlin/Unit| { public final fun test(): R|kotlin/Unit| {
lval f: R|kotlin/reflect/KProperty1<kotlin/Any, kotlin/Int>| = Q|kotlin/Any|?::R|/meaning| lval f: R|kotlin/reflect/KProperty1<kotlin/Any?, kotlin/Int>| = Q|kotlin/Any?|::R|/meaning|
R|<local>/f|.<Inapplicable(INAPPLICABLE): [kotlin/reflect/KProperty1.get]>#(Null(null)) R|<local>/f|.R|FakeOverride<kotlin/reflect/KProperty1.get: R|kotlin/Int|>|(Null(null))
R|<local>/f|.R|FakeOverride<kotlin/reflect/KProperty1.get: R|kotlin/Int|>|(String()) R|<local>/f|.R|FakeOverride<kotlin/reflect/KProperty1.get: R|kotlin/Int|>|(String())
} }
@@ -25,6 +25,7 @@ abstract class FirResolvedQualifier : FirPureAbstractElement(), FirExpression {
abstract val packageFqName: FqName abstract val packageFqName: FqName
abstract val relativeClassFqName: FqName? abstract val relativeClassFqName: FqName?
abstract val classId: ClassId? abstract val classId: ClassId?
abstract val safe: Boolean
abstract val typeArguments: List<FirTypeProjection> abstract val typeArguments: List<FirTypeProjection>
override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitResolvedQualifier(this, data) override fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visitResolvedQualifier(this, data)
@@ -24,7 +24,8 @@ import org.jetbrains.kotlin.fir.visitors.*
class FirResolvedQualifierImpl( class FirResolvedQualifierImpl(
override val source: FirSourceElement?, override val source: FirSourceElement?,
override var packageFqName: FqName, override var packageFqName: FqName,
override var relativeClassFqName: FqName? override var relativeClassFqName: FqName?,
override var safe: Boolean
) : FirResolvedQualifier(), FirAbstractAnnotatedElement { ) : FirResolvedQualifier(), FirAbstractAnnotatedElement {
override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null) override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null)
override val annotations: MutableList<FirAnnotationCall> = mutableListOf() override val annotations: MutableList<FirAnnotationCall> = mutableListOf()
@@ -944,7 +944,7 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) { override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) {
callableReferenceAccess.annotations.renderAnnotations() callableReferenceAccess.annotations.renderAnnotations()
callableReferenceAccess.explicitReceiver?.accept(this) callableReferenceAccess.explicitReceiver?.accept(this)
if (callableReferenceAccess.safe) { if (callableReferenceAccess.safe && callableReferenceAccess.explicitReceiver !is FirResolvedQualifier) {
print("?") print("?")
} }
print("::") print("::")
@@ -1052,6 +1052,9 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() {
} else { } else {
print(resolvedQualifier.packageFqName.asString().replace(".", "/")) print(resolvedQualifier.packageFqName.asString().replace(".", "/"))
} }
if (resolvedQualifier.safe) {
print("?")
}
print("|") print("|")
} }
@@ -323,7 +323,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
} }
impl(resolvedQualifier) { impl(resolvedQualifier) {
isMutable("packageFqName", "relativeClassFqName") isMutable("packageFqName", "relativeClassFqName", "safe")
default("classId") { default("classId") {
value = """ value = """
|relativeClassFqName?.let { |relativeClassFqName?.let {
@@ -435,6 +435,7 @@ object NodeConfigurator : AbstractFieldConfigurator<FirTreeBuilder>(FirTreeBuild
+field("packageFqName", fqNameType) +field("packageFqName", fqNameType)
+field("relativeClassFqName", fqNameType, nullable = true) +field("relativeClassFqName", fqNameType, nullable = true)
+field("classId", classIdType, nullable = true) +field("classId", classIdType, nullable = true)
+booleanField("safe")
+typeArguments.withTransform() +typeArguments.withTransform()
} }
@@ -6,11 +6,11 @@ fun Foo?.bar() {}
fun test() { fun test() {
val r1 = Foo ?:: bar val r1 = Foo ?:: bar
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><(Foo?) -> Unit>(r1) checkSubtype<(Foo?) -> Unit>(r1)
val r2 = Foo ? :: bar val r2 = Foo ? :: bar
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><(Foo?) -> Unit>(r2) checkSubtype<(Foo?) -> Unit>(r2)
val r3 = Foo ? ? :: bar val r3 = Foo ? ? :: bar
<!INAPPLICABLE_CANDIDATE!>checkSubtype<!><(Foo?) -> Unit>(r3) checkSubtype<(Foo?) -> Unit>(r3)
} }
@@ -173,11 +173,11 @@ FILE fqName:<root> fileName:/genericPropertyRef.kt
SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:value2 type:kotlin.Any? visibility:private [static]' type=kotlin.Unit origin=null SET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:value2 type:kotlin.Any? visibility:private [static]' type=kotlin.Unit origin=null
value: GET_VAR 'value: T of <uninitialized parent> declared in <root>.<set-bar>' type=T of <uninitialized parent> origin=null value: GET_VAR 'value: T of <uninitialized parent> declared in <root>.<set-bar>' type=T of <uninitialized parent> origin=null
PROPERTY name:barRef visibility:public modality:FINAL [val] PROPERTY name:barRef visibility:public modality:FINAL [val]
FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1<kotlin.String, kotlin.String> visibility:private [final,static] FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1<kotlin.String?, kotlin.String?> visibility:private [final,static]
EXPRESSION_BODY EXPRESSION_BODY
PROPERTY_REFERENCE 'public final bar: T of <uninitialized parent> [var]' field=null getter='public final fun <get-bar> (): T of <uninitialized parent> declared in <root>' setter='public final fun <set-bar> (value: T of <uninitialized parent>): kotlin.Unit declared in <root>' type=kotlin.reflect.KMutableProperty1<kotlin.String, kotlin.String> origin=null PROPERTY_REFERENCE 'public final bar: T of <uninitialized parent> [var]' field=null getter='public final fun <get-bar> (): T of <uninitialized parent> declared in <root>' setter='public final fun <set-bar> (value: T of <uninitialized parent>): kotlin.Unit declared in <root>' type=kotlin.reflect.KMutableProperty1<kotlin.String?, kotlin.String?> origin=null
FUN DEFAULT_PROPERTY_ACCESSOR name:<get-barRef> visibility:public modality:FINAL <> () returnType:kotlin.reflect.KMutableProperty1<kotlin.String, kotlin.String> FUN DEFAULT_PROPERTY_ACCESSOR name:<get-barRef> visibility:public modality:FINAL <> () returnType:kotlin.reflect.KMutableProperty1<kotlin.String?, kotlin.String?>
correspondingProperty: PROPERTY name:barRef visibility:public modality:FINAL [val] correspondingProperty: PROPERTY name:barRef visibility:public modality:FINAL [val]
BLOCK_BODY BLOCK_BODY
RETURN type=kotlin.Nothing from='public final fun <get-barRef> (): kotlin.reflect.KMutableProperty1<kotlin.String, kotlin.String> declared in <root>' RETURN type=kotlin.Nothing from='public final fun <get-barRef> (): kotlin.reflect.KMutableProperty1<kotlin.String?, kotlin.String?> declared in <root>'
GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1<kotlin.String, kotlin.String> visibility:private [final,static]' type=kotlin.reflect.KMutableProperty1<kotlin.String, kotlin.String> origin=null GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1<kotlin.String?, kotlin.String?> visibility:private [final,static]' type=kotlin.reflect.KMutableProperty1<kotlin.String?, kotlin.String?> origin=null