[FIR] Properly calculate visibilities

`testIntersectionOfPrimitiveBasedFunctions`
is fine, because we deprecate this
already in ^KT-63243.

`CANNOT_INFER_VISIBILITY` is
positioned as `DECLARATION_NAME`,
just in case we decide for
some reason that we do want to
report it along with
`MANY_*_NOT_IMPLEMENTED`. In that
case, we'd get a problem that
their bounds overlap, but not
completely contain one another.

^KT-63741 Fixed
^KT-59400 Fixed
This commit is contained in:
Nikolay Lunyak
2024-01-19 12:44:09 +02:00
committed by Space Team
parent 7056ad5325
commit 8f8c7fe7cf
31 changed files with 203 additions and 139 deletions
@@ -1059,6 +1059,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/PackageQualified.kt");
}
@Test
@TestMetadata("phantomIntersections.kt")
public void testPhantomIntersections() throws Exception {
runTest("compiler/testData/diagnostics/tests/phantomIntersections.kt");
}
@Test
@TestMetadata("prefixIncReturnType.kt")
public void testPrefixIncReturnType() throws Exception {
@@ -26700,12 +26706,6 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/override/kt2052.kt");
}
@Test
@TestMetadata("kt2491.kt")
public void testKt2491() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/kt2491.kt");
}
@Test
@TestMetadata("kt4763.kt")
public void testKt4763() throws Exception {
@@ -1059,6 +1059,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/PackageQualified.kt");
}
@Test
@TestMetadata("phantomIntersections.kt")
public void testPhantomIntersections() throws Exception {
runTest("compiler/testData/diagnostics/tests/phantomIntersections.kt");
}
@Test
@TestMetadata("prefixIncReturnType.kt")
public void testPrefixIncReturnType() throws Exception {
@@ -26706,12 +26712,6 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/override/kt2052.kt");
}
@Test
@TestMetadata("kt2491.kt")
public void testKt2491() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/kt2491.kt");
}
@Test
@TestMetadata("kt4763.kt")
public void testKt4763() throws Exception {
@@ -926,6 +926,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
parameter<FirCallableSymbol<*>>("overridden")
parameter<Name>("containingClassName")
}
val CANNOT_INFER_VISIBILITY by error<KtDeclaration>(PositioningStrategy.DECLARATION_NAME) {
parameter<FirCallableSymbol<*>>("callable")
}
val MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES by error<KtElement>(PositioningStrategy.DECLARATION_SIGNATURE_OR_DEFAULT) {
parameter<Name>("name")
@@ -517,6 +517,7 @@ object FirErrors {
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_CHANGE_ACCESS_PRIVILEGE: KtDiagnosticFactory3<Visibility, FirCallableSymbol<*>, Name> by error3<KtModifierListOwner, Visibility, FirCallableSymbol<*>, Name>(SourceElementPositioningStrategies.VISIBILITY_MODIFIER)
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_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)
@@ -335,6 +335,7 @@ val FIR_NON_SUPPRESSIBLE_ERROR_NAMES: Set<String> = setOf(
"DATA_CLASS_OVERRIDE_DEFAULT_VALUES",
"CANNOT_WEAKEN_ACCESS_PRIVILEGE",
"CANNOT_CHANGE_ACCESS_PRIVILEGE",
"CANNOT_INFER_VISIBILITY",
"MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES",
"MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE",
"TYPEALIAS_EXPANDS_TO_ARRAY_OF_NOTHINGS",
@@ -25,10 +25,6 @@ import org.jetbrains.kotlin.fir.declarations.CallToPotentiallyHiddenSymbolResult
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.originalOrSelf
import org.jetbrains.kotlin.fir.declarations.utils.isFinal
import org.jetbrains.kotlin.fir.declarations.utils.isOverride
import org.jetbrains.kotlin.fir.declarations.utils.modality
import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
@@ -46,7 +42,6 @@ import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.coneType
import org.jetbrains.kotlin.fir.types.typeContext
import org.jetbrains.kotlin.fir.visibilityChecker
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.resolve.deprecation.DeprecationLevelValue
import org.jetbrains.kotlin.resolve.deprecation.SimpleDeprecationInfo
@@ -183,6 +178,16 @@ sealed class FirOverrideChecker(mppKind: MppCheckerKind) : FirAbstractOverrideCh
overriddenSymbols: List<FirCallableSymbol<*>>,
context: CheckerContext
) {
if (visibility == Visibilities.Unknown) {
// MANY_*_NOT_IMPLEMENTED implies CANNOT_INFER_VISIBILITY as per KT-63741
val isManyNotImplementedDiagnosticReported = overriddenSymbols.count { !it.isAbstract } != 1
val isSimpleToReasonAboutSituation = overriddenSymbols.none { it.isIntersectionOverride }
if (!(isManyNotImplementedDiagnosticReported && isSimpleToReasonAboutSituation)) {
reporter.reportOn(source, FirErrors.CANNOT_INFER_VISIBILITY, this, context)
}
return
}
if (overriddenSymbols.isEmpty()) return
val visibilities = overriddenSymbols.map {
it to it.visibility
@@ -124,6 +124,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_BE_IMPORTE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_CHANGE_ACCESS_PRIVILEGE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_CHECK_FOR_ERASED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_INFER_PARAMETER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_INFER_VISIBILITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_OVERRIDE_INVISIBLE_MEMBER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CANNOT_WEAKEN_ACCESS_PRIVILEGE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CAN_BE_REPLACED_WITH_OPERATOR_ASSIGNMENT
@@ -1652,6 +1653,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
DECLARATION_NAME,
TO_STRING
)
map.put(
CANNOT_INFER_VISIBILITY,
"Cannot infer visibility for ''{0}''. Please specify it explicitly",
DECLARATION_NAME,
)
map.put(
ABSTRACT_MEMBER_NOT_IMPLEMENTED,
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
import org.jetbrains.kotlin.utils.addToStdlib.runIf
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
@@ -321,17 +322,52 @@ class FirTypeIntersectionScopeContext(
private fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
extractedOverrides: Collection<MemberWithBaseScope<D>>
): Visibility {
): 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
// TODO: There is more complex logic at org.jetbrains.kotlin.resolve.OverridingUtil.resolveUnknownVisibilityForMember
// TODO: and org.jetbrains.kotlin.resolve.OverridingUtil.findMaxVisibility
val compare = Visibilities.compare(visibility, maxVisibility) ?: return Visibilities.DEFAULT_VISIBILITY
val compare = Visibilities.compare(visibility, maxVisibility) ?: return null
if (compare > 0) {
maxVisibility = visibility
}
}
return maxVisibility
}
@@ -37,6 +37,10 @@ fun Visibility.toEffectiveVisibility(
}
Visibilities.Public -> EffectiveVisibility.Public
Visibilities.Local -> EffectiveVisibility.Local
// Unknown visibility should not provoke errors,
// because they can naturally appear when intersection
// overrides' bases have inconsistent forms.
Visibilities.Unknown -> EffectiveVisibility.Unknown
else -> errorWithAttachment("Unknown visibility: $this") {
withFirLookupTagEntry("owner", owner)
}
@@ -1,5 +1,5 @@
E:
[IntersectionOverride]: public open override fun foo(x: R|kotlin/Int|): R|kotlin/String| from Use site scope of /E [id: 0]
[IntersectionOverride]: public? open override fun foo(x: R|kotlin/Int|): R|kotlin/String| from Use site scope of /E [id: 0]
[SubstitutionOverride(DeclarationSite)]: public open override fun foo(x: R|kotlin/Int!|): R|kotlin/String!| from Use site scope of /C [id: 1]
[SubstitutionOverride(DeclarationSite)]: public open override fun foo(x: R|kotlin/Int!|): R|kotlin/String!| from Substitution scope for [Java enhancement scope for /A] for type C [id: 1]
[Enhancement]: public open fun foo(x: R|ft<T & Any, T?>|): R|kotlin/String!| from Java enhancement scope for /A [id: 2]
@@ -1,11 +0,0 @@
interface T {
public fun foo()
}
open class C {
protected fun foo() {}
}
class D : C(), T
val obj: C = object : C(), T {}
-11
View File
@@ -1,11 +0,0 @@
interface T {
public fun foo()
}
open class C {
protected fun foo() {}
}
class <!CANNOT_INFER_VISIBILITY!>D<!> : C(), T
val obj: C = <!CANNOT_INFER_VISIBILITY!>object<!> : C(), T {}
-26
View File
@@ -1,26 +0,0 @@
package
public val obj: C
public open class C {
public constructor C()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
protected 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
}
public final class D : C, T {
public constructor D()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final override /*2*/ /*fake_override*/ fun foo(): kotlin.Unit
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface T {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public abstract fun foo(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
+4 -2
View File
@@ -1,3 +1,5 @@
// ISSUES: KT-2491, KT-4785, KT-63741, KT-59400
interface T {
fun foo()
}
@@ -6,6 +8,6 @@ open class C {
protected fun foo() {}
}
class E : C(), T
class <!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>E<!> : C(), T
val z: T = object : C(), T {}
val z: T = <!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>object<!> : C(), T {}
@@ -1,3 +1,5 @@
// ISSUES: KT-2491, KT-4785, KT-63741, KT-59400
interface T {
fun foo()
}
@@ -0,0 +1,14 @@
// FIR_IDENTICAL
// ISSUE: KT-63741
interface AreaInstance {
fun getExtensionArea(): Int
}
interface ComponentManager : AreaInstance {
override fun getExtensionArea() = 10
}
interface Project : ComponentManager, AreaInstance
class MockProject : ComponentManager, Project
@@ -1059,6 +1059,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/PackageQualified.kt");
}
@Test
@TestMetadata("phantomIntersections.kt")
public void testPhantomIntersections() throws Exception {
runTest("compiler/testData/diagnostics/tests/phantomIntersections.kt");
}
@Test
@TestMetadata("prefixIncReturnType.kt")
public void testPrefixIncReturnType() throws Exception {
@@ -28954,12 +28960,6 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/override/kt2052.kt");
}
@Test
@TestMetadata("kt2491.kt")
public void testKt2491() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/kt2491.kt");
}
@Test
@TestMetadata("kt4763.kt")
public void testKt4763() throws Exception {