diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt index ac130f71ecf..6527c8ff10e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirCallResolver.kt @@ -207,7 +207,9 @@ class FirCallResolver( when { referencedSymbol is FirClassLikeSymbol<*> -> { 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) resultType = if (classId.isLocal) { typeForQualifierByDeclaration(referencedSymbol.fir, resultType, session) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt index 3d1917f0393..8350268c797 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/FirQualifiedNameResolver.kt @@ -65,7 +65,8 @@ class FirQualifiedNameResolver(components: BodyResolveComponents) : BodyResolveC return FirResolvedQualifierImpl( source, resolved.packageFqName, - resolved.relativeClassFqName + resolved.relativeClassFqName, + safe = false ).apply { resultType = typeForQualifier(this) } } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirDoubleColonExpressionResolver.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirDoubleColonExpressionResolver.kt index 339e814e708..175fcb699a2 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirDoubleColonExpressionResolver.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/FirDoubleColonExpressionResolver.kt @@ -69,7 +69,7 @@ class FirDoubleColonExpressionResolver( private fun shouldTryResolveLHSAsExpression(expression: FirCallableReferenceAccess): Boolean { val lhs = expression.explicitReceiver ?: return false - return lhs.canBeConsideredProperExpression() /* && !expression.hasQuestionMarks */ + return lhs.canBeConsideredProperExpression() && !expression.safe } private fun shouldTryResolveLHSAsType(expression: FirCallableReferenceAccess): Boolean { @@ -168,7 +168,7 @@ class FirDoubleColonExpressionResolver( else -> ConeStarProjection } }, - isNullable = false // TODO: Use org.jetbrains.kotlin.psi.KtDoubleColonExpression.getHasQuestionMarks + isNullable = expression.safe ) return DoubleColonLHS.Type(type) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt index 429a0e15205..22b166c0722 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirExpressionsResolveTransformer.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.FirErrorExpressionImpl 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.references.* import org.jetbrains.kotlin.fir.references.impl.FirErrorNamedReferenceImpl @@ -357,8 +358,12 @@ class FirExpressionsResolveTransformer(transformer: FirBodyResolveTransformer) : } callableReferenceAccess.annotations.forEach { it.accept(this, data) } - val transformedLHS = - callableReferenceAccess.explicitReceiver?.transformSingle(this, ResolutionMode.ContextIndependent) + val explicitReceiver = callableReferenceAccess.explicitReceiver + val transformedLHS = explicitReceiver?.transformSingle(this, ResolutionMode.ContextIndependent)?.apply { + if (this is FirResolvedQualifierImpl && callableReferenceAccess.safe) { + this.safe = true + } + } val callableReferenceAccessWithTransformedLHS = if (transformedLHS != null) diff --git a/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.kt b/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.kt index 6cc15860220..8e91564b898 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.kt +++ b/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.kt @@ -3,6 +3,6 @@ val Any?.meaning: Int fun test() { val f = Any?::meaning - f.get(null) + f.get(null) f.get("") } \ No newline at end of file diff --git a/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.txt b/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.txt index 6c6d2c37b83..6a5db54549b 100644 --- a/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.txt +++ b/compiler/fir/resolve/testData/resolve/stdlib/getOnKProperty.txt @@ -4,7 +4,7 @@ FILE: getOnKProperty.kt ^ Int(42) } public final fun test(): R|kotlin/Unit| { - lval f: R|kotlin/reflect/KProperty1| = Q|kotlin/Any|?::R|/meaning| - R|/f|.#(Null(null)) + lval f: R|kotlin/reflect/KProperty1| = Q|kotlin/Any?|::R|/meaning| + R|/f|.R|FakeOverride|(Null(null)) R|/f|.R|FakeOverride|(String()) } diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirResolvedQualifier.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirResolvedQualifier.kt index 9e5368e8969..367b6ba52ff 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirResolvedQualifier.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/FirResolvedQualifier.kt @@ -25,6 +25,7 @@ abstract class FirResolvedQualifier : FirPureAbstractElement(), FirExpression { abstract val packageFqName: FqName abstract val relativeClassFqName: FqName? abstract val classId: ClassId? + abstract val safe: Boolean abstract val typeArguments: List override fun accept(visitor: FirVisitor, data: D): R = visitor.visitResolvedQualifier(this, data) diff --git a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirResolvedQualifierImpl.kt b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirResolvedQualifierImpl.kt index 7bda07fc9ac..c0a8931b7ce 100644 --- a/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirResolvedQualifierImpl.kt +++ b/compiler/fir/tree/gen/org/jetbrains/kotlin/fir/expressions/impl/FirResolvedQualifierImpl.kt @@ -24,7 +24,8 @@ import org.jetbrains.kotlin.fir.visitors.* class FirResolvedQualifierImpl( override val source: FirSourceElement?, override var packageFqName: FqName, - override var relativeClassFqName: FqName? + override var relativeClassFqName: FqName?, + override var safe: Boolean ) : FirResolvedQualifier(), FirAbstractAnnotatedElement { override var typeRef: FirTypeRef = FirImplicitTypeRefImpl(null) override val annotations: MutableList = mutableListOf() diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt index d606c77bebe..9c670405984 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/FirRenderer.kt @@ -944,7 +944,7 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() { override fun visitCallableReferenceAccess(callableReferenceAccess: FirCallableReferenceAccess) { callableReferenceAccess.annotations.renderAnnotations() callableReferenceAccess.explicitReceiver?.accept(this) - if (callableReferenceAccess.safe) { + if (callableReferenceAccess.safe && callableReferenceAccess.explicitReceiver !is FirResolvedQualifier) { print("?") } print("::") @@ -1052,6 +1052,9 @@ class FirRenderer(builder: StringBuilder) : FirVisitorVoid() { } else { print(resolvedQualifier.packageFqName.asString().replace(".", "/")) } + if (resolvedQualifier.safe) { + print("?") + } print("|") } diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt index ea40382b7ff..da230e93a90 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/ImplementationConfigurator.kt @@ -323,7 +323,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator() } impl(resolvedQualifier) { - isMutable("packageFqName", "relativeClassFqName") + isMutable("packageFqName", "relativeClassFqName", "safe") default("classId") { value = """ |relativeClassFqName?.let { diff --git a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt index b4a917faa44..803a85eaba0 100644 --- a/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt +++ b/compiler/fir/tree/tree-generator/src/org/jetbrains/kotlin/fir/tree/generator/NodeConfigurator.kt @@ -435,6 +435,7 @@ object NodeConfigurator : AbstractFieldConfigurator(FirTreeBuild +field("packageFqName", fqNameType) +field("relativeClassFqName", fqNameType, nullable = true) +field("classId", classIdType, nullable = true) + +booleanField("safe") +typeArguments.withTransform() } diff --git a/compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.fir.kt b/compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.fir.kt index a2505399877..80d7bc794bb 100644 --- a/compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/whitespacesInExpression.fir.kt @@ -6,11 +6,11 @@ fun Foo?.bar() {} fun test() { val r1 = Foo ?:: bar - checkSubtype<(Foo?) -> Unit>(r1) + checkSubtype<(Foo?) -> Unit>(r1) val r2 = Foo ? :: bar - checkSubtype<(Foo?) -> Unit>(r2) + checkSubtype<(Foo?) -> Unit>(r2) val r3 = Foo ? ? :: bar - checkSubtype<(Foo?) -> Unit>(r3) + checkSubtype<(Foo?) -> Unit>(r3) } diff --git a/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt b/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt index 686dcebd356..08ebcf1d4ff 100644 --- a/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt +++ b/compiler/testData/ir/irText/expressions/genericPropertyRef.fir.txt @@ -173,11 +173,11 @@ FILE fqName: fileName:/genericPropertyRef.kt 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 declared in .' type=T of origin=null PROPERTY name:barRef visibility:public modality:FINAL [val] - FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1 visibility:private [final,static] + FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1 visibility:private [final,static] EXPRESSION_BODY - PROPERTY_REFERENCE 'public final bar: T of [var]' field=null getter='public final fun (): T of declared in ' setter='public final fun (value: T of ): kotlin.Unit declared in ' type=kotlin.reflect.KMutableProperty1 origin=null - FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:kotlin.reflect.KMutableProperty1 + PROPERTY_REFERENCE 'public final bar: T of [var]' field=null getter='public final fun (): T of declared in ' setter='public final fun (value: T of ): kotlin.Unit declared in ' type=kotlin.reflect.KMutableProperty1 origin=null + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL <> () returnType:kotlin.reflect.KMutableProperty1 correspondingProperty: PROPERTY name:barRef visibility:public modality:FINAL [val] BLOCK_BODY - RETURN type=kotlin.Nothing from='public final fun (): kotlin.reflect.KMutableProperty1 declared in ' - GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1 visibility:private [final,static]' type=kotlin.reflect.KMutableProperty1 origin=null + RETURN type=kotlin.Nothing from='public final fun (): kotlin.reflect.KMutableProperty1 declared in ' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:barRef type:kotlin.reflect.KMutableProperty1 visibility:private [final,static]' type=kotlin.reflect.KMutableProperty1 origin=null