[FIR] Relax intersection overrides visibility requirements for Java

Allow multiple bases with default
implementations as long as there's a
non-abstract symbol from a class.

Our rules for Kotlin are stricter than
those in Java.
This commit is contained in:
Nikolay Lunyak
2024-02-20 14:48:49 +02:00
committed by Space Team
parent 76ed5453b3
commit da6006b7d0
17 changed files with 159 additions and 100 deletions
@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
import org.jetbrains.kotlin.fir.scopes.PlatformSpecificOverridabilityRules
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
class JavaOverridabilityRules(session: FirSession) : PlatformSpecificOverridabilityRules {
@@ -46,4 +50,9 @@ class JavaOverridabilityRules(session: FirSession) : PlatformSpecificOverridabil
}
private fun FirCallableDeclaration.isOriginallyFromJava(): Boolean = unwrapFakeOverrides().origin == FirDeclarationOrigin.Enhancement
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility = javaOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
}
@@ -5,23 +5,36 @@
package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.dispatchReceiverClassLookupTagOrNull
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractOverrideChecker
import org.jetbrains.kotlin.fir.scopes.impl.chooseIntersectionVisibilityOrNull
import org.jetbrains.kotlin.fir.scopes.impl.filterOutDuplicates
import org.jetbrains.kotlin.fir.scopes.impl.isAbstract
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorRepresentation
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
@@ -357,4 +370,27 @@ class JavaOverrideChecker internal constructor(
return overridesMutableCollectionRemove
}
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility {
val overridesWithoutIntersections = extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }
val nonSubsumed = overridesWithoutIntersections.nonSubsumed().filterOutDuplicates()
// In Java it's OK to inherit multiple implementations of the same function
// from the supertypes as long as there's an implementation from a class.
// We shouldn't reject green Java code.
if (dispatchClassSymbol?.fir is FirJavaClass) {
val nonAbstractFromClass = nonSubsumed.find {
!it.isAbstract && it.member.dispatchReceiverClassLookupTagOrNull()
?.toSymbol(session)?.classKind == ClassKind.CLASS
}
if (nonAbstractFromClass != null) {
return nonAbstractFromClass.member.rawStatus.visibility
}
}
return chooseIntersectionVisibilityOrNull(nonSubsumed) ?: Visibilities.Unknown
}
}