[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
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.analysis.api.fir.diagnostics package org.jetbrains.kotlin.analysis.api.fir.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.KtPsiSourceElement import org.jetbrains.kotlin.KtPsiSourceElement
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.analysis.api.fir.diagnostics package org.jetbrains.kotlin.analysis.api.fir.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
@@ -1928,7 +1927,7 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val containingClassName: Name val containingClassName: Name
} }
interface CannotInferVisibility : KtFirDiagnostic<PsiNameIdentifierOwner> { interface CannotInferVisibility : KtFirDiagnostic<KtDeclaration> {
override val diagnosticClass get() = CannotInferVisibility::class override val diagnosticClass get() = CannotInferVisibility::class
val callable: KtCallableSymbol val callable: KtCallableSymbol
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.analysis.api.fir.diagnostics package org.jetbrains.kotlin.analysis.api.fir.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
@@ -2320,7 +2319,7 @@ internal class CannotInferVisibilityImpl(
override val callable: KtCallableSymbol, override val callable: KtCallableSymbol,
firDiagnostic: KtPsiDiagnostic, firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken, token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiNameIdentifierOwner>(firDiagnostic, token), KtFirDiagnostic.CannotInferVisibility ) : KtAbstractFirDiagnostic<KtDeclaration>(firDiagnostic, token), KtFirDiagnostic.CannotInferVisibility
internal class MultipleDefaultsInheritedFromSupertypesImpl( internal class MultipleDefaultsInheritedFromSupertypesImpl(
override val name: Name, override val name: Name,
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics package org.jetbrains.kotlin.fir.checkers.generator.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind
@@ -927,7 +926,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirCallableSymbol<*>>("overridden") parameter<FirCallableSymbol<*>>("overridden")
parameter<Name>("containingClassName") parameter<Name>("containingClassName")
} }
val CANNOT_INFER_VISIBILITY by error<PsiNameIdentifierOwner>(PositioningStrategy.DECLARATION_NAME) { val CANNOT_INFER_VISIBILITY by error<KtDeclaration>(PositioningStrategy.DECLARATION_NAME) {
parameter<FirCallableSymbol<*>>("callable") parameter<FirCallableSymbol<*>>("callable")
} }
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.PsiNameIdentifierOwner
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.KtSourceElement import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind import org.jetbrains.kotlin.builtins.functions.FunctionTypeKind
@@ -519,7 +518,7 @@ object FirErrors {
val DATA_CLASS_OVERRIDE_DEFAULT_VALUES: KtDiagnosticFactory2<FirCallableSymbol<*>, FirClassSymbol<*>> by error2<KtElement, FirCallableSymbol<*>, FirClassSymbol<*>>(SourceElementPositioningStrategies.DATA_MODIFIER) val DATA_CLASS_OVERRIDE_DEFAULT_VALUES: KtDiagnosticFactory2<FirCallableSymbol<*>, FirClassSymbol<*>> by error2<KtElement, FirCallableSymbol<*>, FirClassSymbol<*>>(SourceElementPositioningStrategies.DATA_MODIFIER)
val CANNOT_WEAKEN_ACCESS_PRIVILEGE: KtDiagnosticFactory3<Visibility, FirCallableSymbol<*>, Name> by error3<KtModifierListOwner, Visibility, FirCallableSymbol<*>, Name>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) val CANNOT_WEAKEN_ACCESS_PRIVILEGE: KtDiagnosticFactory3<Visibility, FirCallableSymbol<*>, Name> by error3<KtModifierListOwner, Visibility, FirCallableSymbol<*>, Name>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
val CANNOT_CHANGE_ACCESS_PRIVILEGE: KtDiagnosticFactory3<Visibility, FirCallableSymbol<*>, Name> by error3<KtModifierListOwner, Visibility, FirCallableSymbol<*>, Name>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER) val CANNOT_CHANGE_ACCESS_PRIVILEGE: KtDiagnosticFactory3<Visibility, FirCallableSymbol<*>, Name> by error3<KtModifierListOwner, Visibility, FirCallableSymbol<*>, Name>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
val CANNOT_INFER_VISIBILITY: KtDiagnosticFactory1<FirCallableSymbol<*>> by error1<PsiNameIdentifierOwner, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME) val CANNOT_INFER_VISIBILITY: KtDiagnosticFactory1<FirCallableSymbol<*>> by error1<KtDeclaration, FirCallableSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES: KtDiagnosticFactory3<Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>> by error3<KtElement, Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES: KtDiagnosticFactory3<Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>> by error3<KtElement, Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE: KtDiagnosticFactory3<Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>> by error3<KtElement, Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_NAME) val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE: KtDiagnosticFactory3<Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>> by error3<KtElement, Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_DEPRECATION: KtDiagnosticFactoryForDeprecation3<Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>> by deprecationError3<KtElement, Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>>(ProhibitAllMultipleDefaultsInheritedFromSupertypes, SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT) val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_DEPRECATION: KtDiagnosticFactoryForDeprecation3<Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>> by deprecationError3<KtElement, Name, FirValueParameterSymbol, List<FirCallableSymbol<*>>>(ProhibitAllMultipleDefaultsInheritedFromSupertypes, SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.fir.java.scopes package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.java.JavaTypeParameterStack 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.scopes.PlatformSpecificOverridabilityRules
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.unwrapFakeOverrides import org.jetbrains.kotlin.fir.unwrapFakeOverrides
class JavaOverridabilityRules(session: FirSession) : PlatformSpecificOverridabilityRules { class JavaOverridabilityRules(session: FirSession) : PlatformSpecificOverridabilityRules {
@@ -46,4 +50,9 @@ class JavaOverridabilityRules(session: FirSession) : PlatformSpecificOverridabil
} }
private fun FirCallableDeclaration.isOriginallyFromJava(): Boolean = unwrapFakeOverrides().origin == FirDeclarationOrigin.Enhancement 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 package org.jetbrains.kotlin.fir.java.scopes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality 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.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.classKind
import org.jetbrains.kotlin.fir.containingClassLookupTag import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isStatic import org.jetbrains.kotlin.fir.declarations.utils.isStatic
import org.jetbrains.kotlin.fir.declarations.utils.modality 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.JavaTypeParameterStack
import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass
import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable import org.jetbrains.kotlin.fir.java.enhancement.readOnlyToMutable
import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible import org.jetbrains.kotlin.fir.java.toConeKotlinTypeProbablyFlexible
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap 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.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractOverrideChecker 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.jvm.computeJvmDescriptorRepresentation
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions 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.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.unwrapFakeOverrides import org.jetbrains.kotlin.fir.unwrapFakeOverrides
@@ -357,4 +370,27 @@ class JavaOverrideChecker internal constructor(
return overridesMutableCollectionRemove 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
}
} }
@@ -5,13 +5,17 @@
package org.jetbrains.kotlin.fir.backend.native package org.jetbrains.kotlin.fir.backend.native
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.native.interop.decodeObjCMethodAnnotation import org.jetbrains.kotlin.fir.backend.native.interop.decodeObjCMethodAnnotation
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker import org.jetbrains.kotlin.fir.scopes.impl.FirStandardOverrideChecker
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
/** /**
* The same code, as in this class also exists in [org.jetbrains.kotlin.ir.objcinterop.ObjCOverridabilityCondition] * The same code, as in this class also exists in [org.jetbrains.kotlin.ir.objcinterop.ObjCOverridabilityCondition]
@@ -30,6 +34,11 @@ class FirNativeOverrideChecker(private val session: FirSession) : FirOverrideChe
// KT-57640: There's no necessity to implement platform-dependent overridability check for properties // KT-57640: There's no necessity to implement platform-dependent overridability check for properties
standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration) standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility = standardOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
/** /**
* mimics ObjCOverridabilityCondition.isOverridable * mimics ObjCOverridabilityCondition.isOverridable
*/ */
@@ -5,10 +5,13 @@
package org.jetbrains.kotlin.fir.scopes package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
/** /**
* That class is expected to work just the same as FirStandardOverrideChecker for regular members, * That class is expected to work just the same as FirStandardOverrideChecker for regular members,
@@ -31,4 +34,12 @@ class FirIntersectionScopeOverrideChecker(session: FirSession) : FirOverrideChec
platformSpecificOverridabilityRules?.isOverriddenProperty(overrideCandidate, baseDeclaration)?.let { return it } platformSpecificOverridabilityRules?.isOverriddenProperty(overrideCandidate, baseDeclaration)?.let { return it }
return standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration) return standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
} }
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility {
platformSpecificOverridabilityRules?.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)?.let { return it }
return standardOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
}
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.scopes package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
@@ -13,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
interface FirOverrideChecker : FirSessionComponent { interface FirOverrideChecker : FirSessionComponent {
fun isOverriddenFunction( fun isOverriddenFunction(
@@ -24,6 +26,11 @@ interface FirOverrideChecker : FirSessionComponent {
overrideCandidate: FirCallableDeclaration, // NB: in Java it can be a function which overrides accessor overrideCandidate: FirCallableDeclaration, // NB: in Java it can be a function which overrides accessor
baseDeclaration: FirProperty baseDeclaration: FirProperty
): Boolean ): Boolean
fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility
} }
fun FirOverrideChecker.isOverriddenFunction( fun FirOverrideChecker.isOverriddenFunction(
@@ -5,11 +5,14 @@
package org.jetbrains.kotlin.fir.scopes package org.jetbrains.kotlin.fir.scopes
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
interface PlatformSpecificOverridabilityRules : FirSessionComponent { interface PlatformSpecificOverridabilityRules : FirSessionComponent {
// Thus functions return "null" in case the status should be defined via standard platform-independent rules // Thus functions return "null" in case the status should be defined via standard platform-independent rules
@@ -22,6 +25,11 @@ interface PlatformSpecificOverridabilityRules : FirSessionComponent {
overrideCandidate: FirCallableDeclaration, overrideCandidate: FirCallableDeclaration,
baseDeclaration: FirProperty baseDeclaration: FirProperty
): Boolean? ): Boolean?
fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility?
} }
val FirSession.platformSpecificOverridabilityRules: PlatformSpecificOverridabilityRules? by FirSession.nullableSessionComponentAccessor() val FirSession.platformSpecificOverridabilityRules: PlatformSpecificOverridabilityRules? by FirSession.nullableSessionComponentAccessor()
@@ -5,10 +5,18 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirResolvedDeclarationStatus
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.fir.unwrapSubstitutionOverrides
import org.jetbrains.kotlin.name.StandardClassIds
fun filterOutOverriddenFunctions(extractedOverridden: Collection<MemberWithBaseScope<FirNamedFunctionSymbol>>): Collection<MemberWithBaseScope<FirNamedFunctionSymbol>> { fun filterOutOverriddenFunctions(extractedOverridden: Collection<MemberWithBaseScope<FirNamedFunctionSymbol>>): Collection<MemberWithBaseScope<FirNamedFunctionSymbol>> {
return filterOutOverridden(extractedOverridden, FirTypeScope::processDirectOverriddenFunctionsWithBaseScope) return filterOutOverridden(extractedOverridden, FirTypeScope::processDirectOverriddenFunctionsWithBaseScope)
@@ -55,3 +63,52 @@ fun <D : FirCallableSymbol<*>> overrides(
return result return result
} }
fun chooseIntersectionVisibilityOrNull(
nonSubsumedOverrides: List<MemberWithBaseScope<FirCallableSymbol<*>>>,
): Visibility? {
val nonAbstract = nonSubsumedOverrides.filter {
// Kotlin's Cloneable interface contains phantom `protected open fun clone()`.
!it.isAbstract && it.member.callableId != StandardClassIds.Callables.clone
}
val allAreAbstract = nonAbstract.isEmpty()
if (allAreAbstract) {
return findMaxVisibilityOrNull(nonSubsumedOverrides)
}
return nonAbstract.singleOrNull()?.member?.rawStatus?.visibility
}
val MemberWithBaseScope<FirCallableSymbol<*>>.isAbstract: Boolean
get() {
// This function is expected to be called during FirResolvePhase.STATUS,
// meaning we can't yet access `resolvedStatus`, because it would require
// the same phase, but by this time we expect the statuses to have been
// calculated de-facto.
require(member.rawStatus is FirResolvedDeclarationStatus)
// Kotlin's Cloneable interface contains phantom `protected open fun clone()`.
return member.rawStatus.modality == Modality.ABSTRACT
}
fun <D : FirCallableSymbol<*>> List<MemberWithBaseScope<D>>.filterOutDuplicates(): List<MemberWithBaseScope<D>> {
val uniqueSymbols = mutableSetOf<FirCallableSymbol<*>>()
return filter { uniqueSymbols.add(it.member.fir.unwrapSubstitutionOverrides().symbol) }
}
fun <D : FirCallableSymbol<*>> findMaxVisibilityOrNull(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility? {
var maxVisibility: Visibility = Visibilities.Private
for ((override) in extractedOverrides) {
val visibility = (override.fir as FirMemberDeclaration).visibility
val compare = Visibilities.compare(visibility, maxVisibility) ?: return null
if (compare > 0) {
maxVisibility = visibility
}
}
return maxVisibility
}
@@ -6,12 +6,16 @@
package org.jetbrains.kotlin.fir.scopes.impl package org.jetbrains.kotlin.fir.scopes.impl
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isSuspend import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
import org.jetbrains.kotlin.fir.declarations.utils.visibility import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration import org.jetbrains.kotlin.fir.resolve.transformers.ensureResolvedTypeDeclaration
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
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.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.types.AbstractTypeChecker import org.jetbrains.kotlin.types.AbstractTypeChecker
@@ -157,4 +161,13 @@ class FirStandardOverrideChecker(private val session: FirSession) : FirAbstractO
isEqualTypes(memberParam.typeRef, selfParam.typeRef, substitutor) isEqualTypes(memberParam.typeRef, selfParam.typeRef, substitutor)
} }
} }
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>,
dispatchClassSymbol: FirRegularClassSymbol?,
): Visibility {
val overridesWithoutIntersections = extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }
val nonSubsumed = overridesWithoutIntersections.nonSubsumed().filterOutDuplicates()
return chooseIntersectionVisibilityOrNull(nonSubsumed) ?: Visibilities.Unknown
}
} }
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.caches.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isExpect import org.jetbrains.kotlin.fir.declarations.utils.isExpect
import org.jetbrains.kotlin.fir.declarations.utils.modality import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve import org.jetbrains.kotlin.fir.resolve.transformers.ReturnTypeCalculatorForFullBodyResolve
import org.jetbrains.kotlin.fir.scopes.* import org.jetbrains.kotlin.fir.scopes.*
@@ -22,7 +21,6 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract import kotlin.contracts.contract
@@ -207,7 +205,7 @@ class FirTypeIntersectionScopeContext(
extractedOverrides: List<MemberWithBaseScope<D>>, extractedOverrides: List<MemberWithBaseScope<D>>,
): MemberWithBaseScope<FirCallableSymbol<*>> { ): MemberWithBaseScope<FirCallableSymbol<*>> {
val newModality = chooseIntersectionOverrideModality(extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }.nonSubsumed()) val newModality = chooseIntersectionOverrideModality(extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }.nonSubsumed())
val newVisibility = chooseIntersectionVisibility(extractedOverrides) val newVisibility = overrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
val mostSpecificSymbols = mostSpecific.map { it.member } val mostSpecificSymbols = mostSpecific.map { it.member }
val extractedOverridesSymbols = extractedOverrides.map { it.member } val extractedOverridesSymbols = extractedOverrides.map { it.member }
val key = mostSpecific.first() val key = mostSpecific.first()
@@ -320,57 +318,6 @@ class FirTypeIntersectionScopeContext(
} }
} }
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility = chooseIntersectionVisibilityOrNull(extractedOverrides) ?: Visibilities.Unknown
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibilityOrNull(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility? {
val overridesWithoutIntersections = extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }
val nonSubsumed = overridesWithoutIntersections.nonSubsumed().filterOutDuplicates()
val nonAbstract = nonSubsumed.filter {
require(it.member.rawStatus is FirResolvedDeclarationStatus) {
"We expect that to be true already, but we can't yet call resolvedStatus"
}
// Kotlin's Cloneable interface contains phantom `protected open fun clone()`.
it.member.rawStatus.modality != Modality.ABSTRACT && it.member.callableId != StandardClassIds.Callables.clone
}
val allAreAbstract = nonAbstract.isEmpty()
if (allAreAbstract) {
return findMaxVisibilityOrNull(nonSubsumed)
}
if (nonAbstract.size >= 2) {
return null
}
return nonAbstract.single().member.rawStatus.visibility
}
private fun <D : FirCallableSymbol<*>> List<MemberWithBaseScope<D>>.filterOutDuplicates(): List<MemberWithBaseScope<D>> {
val uniqueSymbols = mutableSetOf<FirCallableSymbol<*>>()
return filter { uniqueSymbols.add(it.member.fir.unwrapSubstitutionOverrides().symbol) }
}
private fun <D : FirCallableSymbol<*>> findMaxVisibilityOrNull(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility? {
var maxVisibility: Visibility = Visibilities.Private
for ((override) in extractedOverrides) {
val visibility = (override.fir as FirMemberDeclaration).visibility
val compare = Visibilities.compare(visibility, maxVisibility) ?: return null
if (compare > 0) {
maxVisibility = visibility
}
}
return maxVisibility
}
private fun createIntersectionOverrideFunction( private fun createIntersectionOverrideFunction(
mostSpecific: Collection<FirCallableSymbol<*>>, mostSpecific: Collection<FirCallableSymbol<*>>,
overrides: Collection<FirCallableSymbol<*>>, overrides: Collection<FirCallableSymbol<*>>,
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.sure
object PositioningStrategies { object PositioningStrategies {
open class DeclarationHeader<T : PsiElement> : PositioningStrategy<T>() { open class DeclarationHeader<T : KtDeclaration> : PositioningStrategy<T>() {
override fun isValid(element: T): Boolean { override fun isValid(element: T): Boolean {
if (element is KtNamedDeclaration && if (element is KtNamedDeclaration &&
element !is KtObjectDeclaration && element !is KtObjectDeclaration &&
@@ -142,8 +142,8 @@ object PositioningStrategies {
} }
@JvmField @JvmField
val DECLARATION_NAME: PositioningStrategy<PsiNameIdentifierOwner> = object : DeclarationHeader<PsiNameIdentifierOwner>() { val DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
override fun mark(element: PsiNameIdentifierOwner): List<TextRange> { override fun mark(element: KtNamedDeclaration): List<TextRange> {
val nameIdentifier = element.nameIdentifier val nameIdentifier = element.nameIdentifier
if (nameIdentifier != null) { if (nameIdentifier != null) {
if (element is KtClassOrObject) { if (element is KtClassOrObject) {
@@ -1,34 +0,0 @@
// TARGET_BACKEND: JVM
// FILE: IntCollection.java
interface IntCollection<E> {
public boolean add(int key);
}
// FILE: IntSet.java
interface IntSet extends IntCollection {
public default boolean add(Integer it) { return true; }
// from the supertype
// public boolean add(int key);
}
// FILE: AbstractCollection.java
abstract class AbstractCollection<E> {
public boolean add(E it) { return true; }
}
// FILE: AbstractIntCollection.java
abstract class AbstractIntCollection extends AbstractCollection<Integer> {
public boolean add(int it) { return true; }
// from the supertype
// public default boolen add(Integer it) { return true; }
}
// FILE: AbstractIntSet.java
public abstract class AbstractIntSet extends AbstractIntCollection implements IntSet {}
// FILE: Main.kt
<!CANNOT_INFER_VISIBILITY!>class KotlinClass<!> : AbstractIntSet()
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: IntCollection.java // FILE: IntCollection.java