Support nullable callable references in FIR resolve
This commit is contained in:
@@ -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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -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)
|
||||||
|
|||||||
+7
-2
@@ -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)
|
||||||
|
|||||||
+2
-1
@@ -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("|")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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 {
|
||||||
|
|||||||
+1
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user