K2: generate implicit dispatch receivers for static members called

#KT-55371 Fixed
#KT-55372 Fixed
This commit is contained in:
Mikhail Glukhikh
2023-01-16 16:59:33 +01:00
committed by Space Team
parent 9cfcf057ef
commit 4167a69e30
17 changed files with 328 additions and 27 deletions
@@ -34518,6 +34518,18 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStatic.kt");
}
@Test
@TestMetadata("packagePrivateStaticInterfaceMethod.kt")
public void testPackagePrivateStaticInterfaceMethod() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceMethod.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaInternal.kt")
public void testPackagePrivateStaticViaInternal() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticViaInternal.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaTypeAlias.kt")
public void testPackagePrivateStaticViaTypeAlias() throws Exception {
@@ -34614,6 +34614,18 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStatic.kt");
}
@Test
@TestMetadata("packagePrivateStaticInterfaceMethod.kt")
public void testPackagePrivateStaticInterfaceMethod() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceMethod.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaInternal.kt")
public void testPackagePrivateStaticViaInternal() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticViaInternal.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaTypeAlias.kt")
public void testPackagePrivateStaticViaTypeAlias() throws Exception {
@@ -34518,6 +34518,18 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStatic.kt");
}
@Test
@TestMetadata("packagePrivateStaticInterfaceMethod.kt")
public void testPackagePrivateStaticInterfaceMethod() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceMethod.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaInternal.kt")
public void testPackagePrivateStaticViaInternal() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticViaInternal.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaTypeAlias.kt")
public void testPackagePrivateStaticViaTypeAlias() throws Exception {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
@@ -36,7 +37,10 @@ object FirVisibilityQualifierChecker : FirResolvedQualifierChecker() {
val firFile = context.containingFile ?: return
val firClassLikeDeclaration = symbol.fir
if (!context.session.visibilityChecker.isClassLikeVisible(
// Note: errors on implicit receiver are already reported in coneDiagnosticToFirDiagnostic
// See e.g. diagnostics/tests/visibility/packagePrivateStaticViaInternal.fir.kt
if (expression.source?.kind != KtFakeSourceElementKind.ImplicitReceiver &&
!context.session.visibilityChecker.isClassLikeVisible(
firClassLikeDeclaration, context.session, firFile, context.containingDeclarations,
)
) {
@@ -28962,12 +28962,24 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/javaVisibility/package"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("cannotAccessInterfaceMemberViaReceiver.kt")
public void testCannotAccessInterfaceMemberViaReceiver() throws Exception {
runTest("compiler/testData/codegen/box/javaVisibility/package/cannotAccessInterfaceMemberViaReceiver.kt");
}
@Test
@TestMetadata("cannotAccessStaticMemberViaReceiver.kt")
public void testCannotAccessStaticMemberViaReceiver() throws Exception {
runTest("compiler/testData/codegen/box/javaVisibility/package/cannotAccessStaticMemberViaReceiver.kt");
}
@Test
@TestMetadata("cannotAccessStaticMemberViaReceiver2.kt")
public void testCannotAccessStaticMemberViaReceiver2() throws Exception {
runTest("compiler/testData/codegen/box/javaVisibility/package/cannotAccessStaticMemberViaReceiver2.kt");
}
@Test
@TestMetadata("cannotAccessStaticMemberViaTypeAlias.kt")
public void testCannotAccessStaticMemberViaTypeAlias() throws Exception {
@@ -5,6 +5,10 @@
package org.jetbrains.kotlin.fir.resolve.calls.tower
import org.jetbrains.kotlin.KtFakeSourceElementKind
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.fakeElement
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.declarations.ContextReceiverGroup
import org.jetbrains.kotlin.fir.declarations.FirConstructor
@@ -327,38 +331,69 @@ class ScopeTowerLevel(
fun areThereExtensionReceiverOptions(): Boolean = givenExtensionReceiverOptions.isNotEmpty()
private fun dispatchReceiverValue(candidate: FirCallableSymbol<*>): ReceiverValue? {
private fun FirRegularClassSymbol.toResolvedQualifierExpressionReceiver(source: KtSourceElement?): ExpressionReceiverValue {
val resolvedQualifier = buildResolvedQualifier {
packageFqName = classId.packageFqName
relativeClassFqName = classId.relativeClassName
this.symbol = this@toResolvedQualifierExpressionReceiver
this.source = source?.fakeElement(KtFakeSourceElementKind.ImplicitReceiver)
}.apply {
resultType = bodyResolveComponents.typeForQualifier(this)
}
return ExpressionReceiverValue(resolvedQualifier)
}
private fun FirRegularClassSymbol.findJavaSuperClassSymbol(): FirRegularClassSymbol? {
var currentSymbol = this
while (currentSymbol.origin !is FirDeclarationOrigin.Java) {
var baseClassSymbol: FirRegularClassSymbol? = null
for (superType in currentSymbol.resolvedSuperTypes) {
val symbol = superType.fullyExpandedType(session).toSymbol(session)
if (symbol is FirRegularClassSymbol && symbol.classKind == ClassKind.CLASS) {
baseClassSymbol = symbol
break
}
}
currentSymbol = baseClassSymbol ?: return null
}
return currentSymbol
}
private fun dispatchReceiverValue(candidate: FirCallableSymbol<*>, callInfo: CallInfo): ReceiverValue? {
candidate.fir.importedFromObjectOrStaticData?.let { data ->
val objectClassId = data.objectClassId
val symbol = session.symbolProvider.getClassLikeSymbolByClassId(objectClassId)
if (symbol is FirRegularClassSymbol) {
val resolvedQualifier = buildResolvedQualifier {
packageFqName = objectClassId.packageFqName
relativeClassFqName = objectClassId.relativeClassName
this.symbol = symbol
}.apply {
resultType = bodyResolveComponents.typeForQualifier(this)
}
return ExpressionReceiverValue(resolvedQualifier)
return symbol.toResolvedQualifierExpressionReceiver(callInfo.callSite.source)
}
}
if (candidate !is FirBackingFieldSymbol) {
return null
}
if (candidate is FirBackingFieldSymbol) {
val lookupTag = candidate.fir.propertySymbol.dispatchReceiverClassLookupTagOrNull()
return when {
lookupTag != null -> {
bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver { implicitReceiverValue ->
(implicitReceiverValue.type as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag == lookupTag
}
}
val lookupTag = candidate.fir.propertySymbol.dispatchReceiverClassLookupTagOrNull()
return when {
lookupTag != null -> {
bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver { implicitReceiverValue ->
(implicitReceiverValue.type as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag == lookupTag
else -> {
bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver()
}
}
else -> {
bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver()
}
}
if (candidate.isStatic && callInfo.explicitReceiver == null && candidate.isJavaOrEnhancement) {
val lookupTag = candidate.fir.containingClassLookupTag() ?: return null
val implicitDispatchReceiverValue = bodyResolveComponents.implicitReceiverStack.lastDispatchReceiver { implicitReceiverValue ->
implicitReceiverValue is ImplicitDispatchReceiverValue && implicitReceiverValue.boundSymbol.fir.isSubclassOf(
lookupTag, session, isStrict = false, lookupInterfaces = false
)
} ?: return null
// Note: we know that candidate is from Java, so normally we should find this class and its Java superclass
val regularClassSymbol = implicitDispatchReceiverValue.boundSymbol as? FirRegularClassSymbol ?: return null
return regularClassSymbol.findJavaSuperClassSymbol()?.toResolvedQualifierExpressionReceiver(callInfo.callSite.source)
}
return null
}
private fun shouldSkipCandidateWithInconsistentExtensionReceiver(candidate: FirCallableSymbol<*>): Boolean {
@@ -386,6 +421,7 @@ class ScopeTowerLevel(
private fun <T : FirBasedSymbol<*>> consumeCallableCandidate(
candidate: FirCallableSymbol<*>,
callInfo: CallInfo,
processor: TowerScopeLevelProcessor<T>
) {
val candidateReceiverTypeRef = candidate.fir.receiverParameter?.typeRef
@@ -394,7 +430,7 @@ class ScopeTowerLevel(
}
val receiverExpected = withHideMembersOnly || areThereExtensionReceiverOptions()
if (candidateReceiverTypeRef == null == receiverExpected) return
val dispatchReceiverValue = dispatchReceiverValue(candidate)
val dispatchReceiverValue = dispatchReceiverValue(candidate, callInfo)
if (dispatchReceiverValue == null && shouldSkipCandidateWithInconsistentExtensionReceiver(candidate)) {
return
}
@@ -421,7 +457,7 @@ class ScopeTowerLevel(
includeInnerConstructors = includeInnerConstructors
) { candidate ->
empty = false
consumeCallableCandidate(candidate, processor)
consumeCallableCandidate(candidate, info, processor)
}
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
}
@@ -434,7 +470,7 @@ class ScopeTowerLevel(
session.lookupTracker?.recordCallLookup(info, scope.scopeOwnerLookupNames)
scope.processPropertiesByName(info.name) { candidate ->
empty = false
consumeCallableCandidate(candidate, processor)
consumeCallableCandidate(candidate, info, processor)
}
return if (empty) ProcessResult.SCOPE_EMPTY else ProcessResult.FOUND
}
@@ -237,6 +237,9 @@ sealed class KtFakeSourceElementKind : KtSourceElementKind() {
// for extension receiver type the corresponding receiver parameter is generated
// with a fake sources which refers to this the type
object ReceiverFromType : KtFakeSourceElementKind()
// for all implicit receivers (now used for qualifiers only)
object ImplicitReceiver : KtFakeSourceElementKind()
}
sealed class AbstractKtSourceElement {
@@ -0,0 +1,28 @@
// TARGET_BACKEND: JVM_IR
// FILE: javapackage/PackagePrivateGrandparentAbstractClass.java
package javapackage;
/*package-private*/ interface PackagePrivateGrandparentInterface {
String publicStaticField = "OK";
}
// FILE: javapackage/PublicParentClass.java
package javapackage;
public class PublicParentClass implements PackagePrivateGrandparentInterface {}
// FILE: Child.kt
import javapackage.PublicParentClass
class Child : PublicParentClass() {
fun foo(): String {
return publicStaticField
}
}
// FILE: test.kt
fun box() = Child().foo()
@@ -1,6 +1,4 @@
// TARGET_BACKEND: JVM_IR
// IGNORE_BACKEND_K2: JVM_IR
// See KT-55371
// FILE: javapackage/PackagePrivateGrandparentAbstractClass.java
package javapackage;
@@ -0,0 +1,31 @@
// TARGET_BACKEND: JVM_IR
// FILE: javapackage/PackagePrivateGrandparentAbstractClass.java
package javapackage;
/*package-private*/ abstract class PackagePrivateGrandparentAbstractClass {
public static void publicStaticMethod() {}
public static String publicStaticField = "OK";
}
// FILE: javapackage/PublicParentClass.java
package javapackage;
public class PublicParentClass extends PackagePrivateGrandparentAbstractClass {}
// FILE: Child.kt
typealias Base = javapackage.PublicParentClass
class Child : Base() {
fun foo(): String {
publicStaticMethod()
return publicStaticField
}
}
// FILE: test.kt
fun box() = Child().foo()
@@ -0,0 +1,28 @@
// FIR_IDENTICAL
// FILE: javapackage/PackagePrivateGrandparentAbstractClass.java
package javapackage;
/*package-private*/ interface PackagePrivateGrandparentInterface {
static void publicStaticMethod() {}
String publicStaticField = "OK";
}
// FILE: javapackage/PublicParentClass.java
package javapackage;
public class PublicParentClass implements PackagePrivateGrandparentInterface {}
// FILE: Child.kt
import javapackage.PublicParentClass
class Child : PublicParentClass() {
fun foo(): String {
<!UNRESOLVED_REFERENCE!>publicStaticMethod<!>() // Error!
PublicParentClass.<!UNRESOLVED_REFERENCE!>publicStaticMethod<!>() // Error!
return publicStaticField // Ok!
}
}
@@ -0,0 +1,32 @@
package
public final class Child : javapackage.PublicParentClass {
public constructor Child()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package javapackage {
public/*package*/ interface PackagePrivateGrandparentInterface {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public const final val publicStaticField: kotlin.String = "OK"
public open fun publicStaticMethod(): kotlin.Unit
}
public open class PublicParentClass : javapackage.PackagePrivateGrandparentInterface {
public constructor PublicParentClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public const final override /*1*/ /*fake_override*/ val publicStaticField: kotlin.String = "OK"
}
}
@@ -0,0 +1,20 @@
// FILE: javapackage/PackagePrivateGrandparentAbstractClass.java
package javapackage;
/*package-private*/ abstract class PackagePrivateGrandparentAbstractClass {
public static void publicStaticMethod() {}
}
// FILE: javapackage/KotlinParentClass.kt
package javapackage
internal open class KotlinParentClass : PackagePrivateGrandparentAbstractClass()
// FILE: Child.kt
import javapackage.KotlinParentClass
internal class Child : KotlinParentClass() {
fun foo() {
<!INVISIBLE_REFERENCE!>publicStaticMethod<!>()
}
}
@@ -0,0 +1,20 @@
// FILE: javapackage/PackagePrivateGrandparentAbstractClass.java
package javapackage;
/*package-private*/ abstract class PackagePrivateGrandparentAbstractClass {
public static void publicStaticMethod() {}
}
// FILE: javapackage/KotlinParentClass.kt
package javapackage
internal open class KotlinParentClass : PackagePrivateGrandparentAbstractClass()
// FILE: Child.kt
import javapackage.KotlinParentClass
internal class Child : KotlinParentClass() {
fun foo() {
<!INVISIBLE_MEMBER!>publicStaticMethod<!>()
}
}
@@ -0,0 +1,29 @@
package
internal final class Child : javapackage.KotlinParentClass {
public constructor Child()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package javapackage {
internal open class KotlinParentClass : javapackage.PackagePrivateGrandparentAbstractClass {
public constructor KotlinParentClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public/*package*/ abstract class PackagePrivateGrandparentAbstractClass {
public/*package*/ constructor PackagePrivateGrandparentAbstractClass()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
// Static members
public open fun publicStaticMethod(): kotlin.Unit
}
}
@@ -34614,6 +34614,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStatic.kt");
}
@Test
@TestMetadata("packagePrivateStaticInterfaceMethod.kt")
public void testPackagePrivateStaticInterfaceMethod() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticInterfaceMethod.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaInternal.kt")
public void testPackagePrivateStaticViaInternal() throws Exception {
runTest("compiler/testData/diagnostics/tests/visibility/packagePrivateStaticViaInternal.kt");
}
@Test
@TestMetadata("packagePrivateStaticViaTypeAlias.kt")
public void testPackagePrivateStaticViaTypeAlias() throws Exception {
@@ -28962,12 +28962,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/javaVisibility/package"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("cannotAccessInterfaceMemberViaReceiver.kt")
public void testCannotAccessInterfaceMemberViaReceiver() throws Exception {
runTest("compiler/testData/codegen/box/javaVisibility/package/cannotAccessInterfaceMemberViaReceiver.kt");
}
@Test
@TestMetadata("cannotAccessStaticMemberViaReceiver.kt")
public void testCannotAccessStaticMemberViaReceiver() throws Exception {
runTest("compiler/testData/codegen/box/javaVisibility/package/cannotAccessStaticMemberViaReceiver.kt");
}
@Test
@TestMetadata("cannotAccessStaticMemberViaReceiver2.kt")
public void testCannotAccessStaticMemberViaReceiver2() throws Exception {
runTest("compiler/testData/codegen/box/javaVisibility/package/cannotAccessStaticMemberViaReceiver2.kt");
}
@Test
@TestMetadata("cannotAccessStaticMemberViaTypeAlias.kt")
public void testCannotAccessStaticMemberViaTypeAlias() throws Exception {