[FIR] Calculate property setters visibilities for intersections properly
Basically, just calculate them the same way it's done for other members. `chooseIntersectionVisibilityForSymbolsOrNull` is named like this to prevent a JVM clash. ^KT-66046 Fixed
This commit is contained in:
committed by
Space Team
parent
b7926b68ab
commit
7ecbaf7d1e
+3
-4
@@ -12,7 +12,6 @@ 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
|
||||
@@ -51,8 +50,8 @@ class JavaOverridabilityRules(session: FirSession) : PlatformSpecificOverridabil
|
||||
|
||||
private fun FirCallableDeclaration.isOriginallyFromJava(): Boolean = unwrapFakeOverrides().origin == FirDeclarationOrigin.Enhancement
|
||||
|
||||
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
override fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility = javaOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
|
||||
): Visibility = javaOverrideChecker.chooseIntersectionVisibility(overrides, dispatchClassSymbol)
|
||||
}
|
||||
|
||||
@@ -25,11 +25,8 @@ 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.isAbstract
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorRepresentation
|
||||
import org.jetbrains.kotlin.fir.scopes.processOverriddenFunctions
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
@@ -370,25 +367,23 @@ class JavaOverrideChecker internal constructor(
|
||||
return overridesMutableCollectionRemove
|
||||
}
|
||||
|
||||
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
override fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility {
|
||||
val nonSubsumed = extractedOverrides.getNonSubsumedNonPhantomOverriddenSymbols()
|
||||
|
||||
// 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()
|
||||
val nonAbstractFromClass = overrides.find {
|
||||
!it.isAbstractAccordingToRawStatus && it.dispatchReceiverClassLookupTagOrNull()
|
||||
?.toSymbol(session)?.classKind == ClassKind.CLASS
|
||||
}
|
||||
if (nonAbstractFromClass != null) {
|
||||
return nonAbstractFromClass.member.rawStatus.visibility
|
||||
return nonAbstractFromClass.rawStatus.visibility
|
||||
}
|
||||
}
|
||||
|
||||
return chooseIntersectionVisibilityOrNull(nonSubsumed) ?: Visibilities.Unknown
|
||||
return chooseIntersectionVisibilityOrNull(overrides) ?: Visibilities.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
+3
-5
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
import org.jetbrains.kotlin.fir.scopes.MemberWithBaseScope
|
||||
import org.jetbrains.kotlin.fir.scopes.impl.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
|
||||
@@ -38,12 +37,11 @@ class FirNativeOverrideChecker(private val session: FirSession) : FirOverrideChe
|
||||
// KT-57640: There's no necessity to implement platform-dependent overridability check for properties
|
||||
standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||
|
||||
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
override fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility {
|
||||
val nonSubsumed = extractedOverrides.getNonSubsumedNonPhantomOverriddenSymbols()
|
||||
return chooseIntersectionVisibilityOrNull(nonSubsumed) { it.isAbstract || it.member.isObjCClassProperty(session) }
|
||||
return chooseIntersectionVisibilityOrNull(overrides) { it.isAbstractAccordingToRawStatus || it.isObjCClassProperty(session) }
|
||||
?: Visibilities.Unknown
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -35,11 +35,11 @@ class FirIntersectionScopeOverrideChecker(session: FirSession) : FirOverrideChec
|
||||
return standardOverrideChecker.isOverriddenProperty(overrideCandidate, baseDeclaration)
|
||||
}
|
||||
|
||||
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
override fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility {
|
||||
platformSpecificOverridabilityRules?.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)?.let { return it }
|
||||
return standardOverrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
|
||||
platformSpecificOverridabilityRules?.chooseIntersectionVisibility(overrides, dispatchClassSymbol)?.let { return it }
|
||||
return standardOverrideChecker.chooseIntersectionVisibility(overrides, dispatchClassSymbol)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ interface FirOverrideChecker : FirSessionComponent {
|
||||
baseDeclaration: FirProperty
|
||||
): Boolean
|
||||
|
||||
fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility
|
||||
}
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ interface PlatformSpecificOverridabilityRules : FirSessionComponent {
|
||||
baseDeclaration: FirProperty
|
||||
): Boolean?
|
||||
|
||||
fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility?
|
||||
}
|
||||
|
||||
+21
-13
@@ -399,6 +399,7 @@ object FirFakeOverrideGenerator {
|
||||
newReturnType: ConeKotlinType? = null,
|
||||
newModality: Modality? = null,
|
||||
newVisibility: Visibility? = null,
|
||||
newSetterVisibility: Visibility? = null,
|
||||
deferredReturnTypeCalculation: DeferredCallableCopyReturnType? = null,
|
||||
newSource: KtSourceElement? = derivedClassLookupTag?.toSymbol(session)?.source,
|
||||
): FirProperty = buildProperty {
|
||||
@@ -436,16 +437,19 @@ object FirFakeOverrideGenerator {
|
||||
newSource = newSource ?: baseProperty.getter?.source,
|
||||
)
|
||||
|
||||
setter = baseProperty.setter?.buildCopyIfNeeded(
|
||||
moduleData = session.nullableModuleData ?: baseProperty.moduleData,
|
||||
origin = origin,
|
||||
propertyReturnTypeRef = this@buildProperty.returnTypeRef,
|
||||
propertySymbol = newSymbol,
|
||||
dispatchReceiverType = dispatchReceiverType,
|
||||
derivedClassLookupTag = derivedClassLookupTag,
|
||||
baseProperty = baseProperty,
|
||||
newSource = newSource ?: baseProperty.setter?.source,
|
||||
)
|
||||
setter = baseProperty.setter?.let { setter ->
|
||||
setter.buildCopyIfNeeded(
|
||||
moduleData = session.nullableModuleData ?: baseProperty.moduleData,
|
||||
origin = origin,
|
||||
propertyReturnTypeRef = this@buildProperty.returnTypeRef,
|
||||
propertySymbol = newSymbol,
|
||||
dispatchReceiverType = dispatchReceiverType,
|
||||
derivedClassLookupTag = derivedClassLookupTag,
|
||||
baseProperty = baseProperty,
|
||||
newSource = newSource ?: baseProperty.setter?.source,
|
||||
newSetterVisibility ?: setter.visibility,
|
||||
)
|
||||
}
|
||||
}.apply {
|
||||
containingClassForStaticMemberAttr = derivedClassLookupTag.takeIf { shouldOverrideSetContainingClass(baseProperty) }
|
||||
}
|
||||
@@ -459,8 +463,9 @@ object FirFakeOverrideGenerator {
|
||||
derivedClassLookupTag: ConeClassLikeLookupTag?,
|
||||
baseProperty: FirProperty,
|
||||
newSource: KtSourceElement? = source,
|
||||
newVisibility: Visibility = visibility,
|
||||
) = when {
|
||||
annotations.isNotEmpty() || visibility != baseProperty.visibility -> buildCopy(
|
||||
annotations.isNotEmpty() || newVisibility != baseProperty.visibility -> buildCopy(
|
||||
moduleData,
|
||||
origin,
|
||||
propertyReturnTypeRef,
|
||||
@@ -469,6 +474,7 @@ object FirFakeOverrideGenerator {
|
||||
derivedClassLookupTag,
|
||||
baseProperty,
|
||||
newSource,
|
||||
newVisibility,
|
||||
)
|
||||
else -> null
|
||||
}
|
||||
@@ -482,13 +488,14 @@ object FirFakeOverrideGenerator {
|
||||
derivedClassLookupTag: ConeClassLikeLookupTag?,
|
||||
baseProperty: FirProperty,
|
||||
newSource: KtSourceElement? = source,
|
||||
newVisibility: Visibility = visibility,
|
||||
) = when (this) {
|
||||
is FirDefaultPropertyGetter -> FirDefaultPropertyGetter(
|
||||
source = newSource,
|
||||
moduleData = moduleData,
|
||||
origin = origin,
|
||||
propertyTypeRef = propertyReturnTypeRef,
|
||||
visibility = visibility,
|
||||
visibility = newVisibility,
|
||||
propertySymbol = propertySymbol,
|
||||
modality = modality ?: Modality.FINAL,
|
||||
effectiveVisibility = effectiveVisibility,
|
||||
@@ -501,7 +508,7 @@ object FirFakeOverrideGenerator {
|
||||
moduleData = moduleData,
|
||||
origin = origin,
|
||||
propertyTypeRef = propertyReturnTypeRef,
|
||||
visibility = visibility,
|
||||
visibility = newVisibility,
|
||||
propertySymbol = propertySymbol,
|
||||
modality = modality ?: Modality.FINAL,
|
||||
effectiveVisibility = effectiveVisibility,
|
||||
@@ -518,6 +525,7 @@ object FirFakeOverrideGenerator {
|
||||
this.dispatchReceiverType = dispatchReceiverType
|
||||
this.body = null
|
||||
resolvePhase = origin.resolvePhaseForCopy
|
||||
this.status = status.copy(visibility = newVisibility)
|
||||
}.also {
|
||||
if (it.isSetter) {
|
||||
val originalParameter = it.valueParameters.first()
|
||||
|
||||
+28
-13
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.scopes.*
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.name.StandardClassIds
|
||||
|
||||
@@ -64,40 +65,54 @@ fun <D : FirCallableSymbol<*>> overrides(
|
||||
}
|
||||
|
||||
inline fun chooseIntersectionVisibilityOrNull(
|
||||
nonSubsumedOverrides: List<MemberWithBaseScope<FirCallableSymbol<*>>>,
|
||||
isAbstract: (MemberWithBaseScope<FirCallableSymbol<*>>) -> Boolean = MemberWithBaseScope<FirCallableSymbol<*>>::isAbstract,
|
||||
nonSubsumedOverrides: Collection<FirCallableSymbol<*>>,
|
||||
isAbstract: (FirCallableSymbol<*>) -> Boolean = FirCallableSymbol<*>::isAbstractAccordingToRawStatus,
|
||||
): Visibility? = chooseIntersectionVisibilityOrNull(
|
||||
nonSubsumedOverrides,
|
||||
toSymbol = { it },
|
||||
isAbstract,
|
||||
)
|
||||
|
||||
inline fun <D> chooseIntersectionVisibilityOrNull(
|
||||
nonSubsumedOverrides: Collection<D>,
|
||||
toSymbol: (D) -> FirCallableSymbol<*>,
|
||||
isAbstract: (D) -> Boolean,
|
||||
): Visibility? {
|
||||
val nonAbstract = nonSubsumedOverrides.filter {
|
||||
// Kotlin's Cloneable interface contains phantom `protected open fun clone()`.
|
||||
!isAbstract(it) && it.member.callableId != StandardClassIds.Callables.clone
|
||||
!isAbstract(it) && toSymbol(it).callableId != StandardClassIds.Callables.clone
|
||||
}
|
||||
val allAreAbstract = nonAbstract.isEmpty()
|
||||
|
||||
if (allAreAbstract) {
|
||||
return findMaxVisibilityOrNull(nonSubsumedOverrides)
|
||||
return findMaxVisibilityOrNull(nonSubsumedOverrides, toSymbol)
|
||||
}
|
||||
|
||||
return nonAbstract.singleOrNull()?.member?.rawStatus?.visibility
|
||||
return nonAbstract.singleOrNull()?.let(toSymbol)?.rawStatus?.visibility
|
||||
}
|
||||
|
||||
val MemberWithBaseScope<FirCallableSymbol<*>>.isAbstract: Boolean
|
||||
val FirCallableSymbol<*>.isAbstractAccordingToRawStatus: Boolean
|
||||
get() {
|
||||
val responsibleDeclaration = when (this) {
|
||||
!is FirPropertyAccessorSymbol -> this
|
||||
else -> propertySymbol
|
||||
}
|
||||
// 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
|
||||
require(responsibleDeclaration.rawStatus is FirResolvedDeclarationStatus)
|
||||
return responsibleDeclaration.rawStatus.modality == Modality.ABSTRACT
|
||||
}
|
||||
|
||||
fun <D : FirCallableSymbol<*>> findMaxVisibilityOrNull(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>
|
||||
inline fun <D> findMaxVisibilityOrNull(
|
||||
extractedOverrides: Collection<D>,
|
||||
toSymbol: (D) -> FirCallableSymbol<*>,
|
||||
): Visibility? {
|
||||
var maxVisibility: Visibility = Visibilities.Private
|
||||
|
||||
for ((override) in extractedOverrides) {
|
||||
val visibility = (override.fir as FirMemberDeclaration).visibility
|
||||
for (override in extractedOverrides) {
|
||||
val visibility = (toSymbol(override).fir as FirMemberDeclaration).visibility
|
||||
val compare = Visibilities.compare(visibility, maxVisibility) ?: return null
|
||||
|
||||
if (compare > 0) {
|
||||
|
||||
+3
-5
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.isSuspend
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
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
|
||||
@@ -162,11 +161,10 @@ class FirStandardOverrideChecker(private val session: FirSession) : FirAbstractO
|
||||
}
|
||||
}
|
||||
|
||||
override fun <D : FirCallableSymbol<*>> chooseIntersectionVisibility(
|
||||
extractedOverrides: Collection<MemberWithBaseScope<D>>,
|
||||
override fun chooseIntersectionVisibility(
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
dispatchClassSymbol: FirRegularClassSymbol?,
|
||||
): Visibility {
|
||||
val nonSubsumed = extractedOverrides.getNonSubsumedNonPhantomOverriddenSymbols()
|
||||
return chooseIntersectionVisibilityOrNull(nonSubsumed) ?: Visibilities.Unknown
|
||||
return chooseIntersectionVisibilityOrNull(overrides) ?: Visibilities.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
+14
-2
@@ -215,7 +215,8 @@ class FirTypeIntersectionScopeContext(
|
||||
containsMultipleNonSubsumed: Boolean,
|
||||
): MemberWithBaseScope<FirCallableSymbol<*>> {
|
||||
val newModality = chooseIntersectionOverrideModality(extractedOverrides.flatMap { it.flattenIntersectionsRecursively() }.nonSubsumed())
|
||||
val newVisibility = overrideChecker.chooseIntersectionVisibility(extractedOverrides, dispatchClassSymbol)
|
||||
val nonSubsumedNonPhantomOverrides = extractedOverrides.getNonSubsumedNonPhantomOverriddenSymbols().map { it.member }
|
||||
val newVisibility = overrideChecker.chooseIntersectionVisibility(nonSubsumedNonPhantomOverrides, dispatchClassSymbol)
|
||||
val mostSpecificSymbols = mostSpecific.map { it.member }
|
||||
val extractedOverridesSymbols = extractedOverrides.map { it.member }
|
||||
val key = mostSpecific.first()
|
||||
@@ -227,7 +228,8 @@ class FirTypeIntersectionScopeContext(
|
||||
|
||||
is FirPropertySymbol ->
|
||||
createIntersectionOverrideProperty(
|
||||
mostSpecificSymbols, extractedOverridesSymbols, newModality, newVisibility, containsMultipleNonSubsumed
|
||||
mostSpecificSymbols, extractedOverridesSymbols, nonSubsumedNonPhantomOverrides, newModality,
|
||||
newVisibility, containsMultipleNonSubsumed,
|
||||
)
|
||||
|
||||
is FirFieldSymbol -> {
|
||||
@@ -368,6 +370,7 @@ class FirTypeIntersectionScopeContext(
|
||||
private fun createIntersectionOverrideProperty(
|
||||
mostSpecific: Collection<FirCallableSymbol<*>>,
|
||||
overrides: Collection<FirCallableSymbol<*>>,
|
||||
nonSubsumedNonPhantomOverrides: List<FirCallableSymbol<*>>,
|
||||
newModality: Modality?,
|
||||
newVisibility: Visibility,
|
||||
containsMultipleNonSubsumed: Boolean,
|
||||
@@ -378,6 +381,14 @@ class FirTypeIntersectionScopeContext(
|
||||
containsMultipleNonSubsumed,
|
||||
::FirIntersectionOverridePropertySymbol,
|
||||
) { symbol, fir, deferredReturnTypeCalculation, returnType ->
|
||||
// Only setters's visibilities are calculated properly, because
|
||||
// getters' visibilities must be the same as the ones of their
|
||||
// properties and those we've already calculated.
|
||||
val setters = nonSubsumedNonPhantomOverrides.mapNotNull {
|
||||
(it as? FirPropertySymbol)?.unwrapSubstitutionOverrides()?.setterSymbol
|
||||
}
|
||||
val setterVisibility = chooseIntersectionVisibilityOrNull(setters) ?: Visibilities.Unknown
|
||||
|
||||
FirFakeOverrideGenerator.createCopyForFirProperty(
|
||||
symbol, fir, derivedClassLookupTag = null, session,
|
||||
FirDeclarationOrigin.IntersectionOverride,
|
||||
@@ -390,6 +401,7 @@ class FirTypeIntersectionScopeContext(
|
||||
// anyway and their uses should result in an overload resolution error.
|
||||
newReturnType = returnType,
|
||||
newSource = dispatchReceiverType.toSymbol(session)?.source,
|
||||
newSetterVisibility = setterVisibility,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
-22
@@ -1,22 +0,0 @@
|
||||
// ISSUE: KT-66046
|
||||
|
||||
abstract class I1 {
|
||||
abstract var a: Int
|
||||
protected set
|
||||
}
|
||||
|
||||
interface I2 {
|
||||
var a: Int
|
||||
}
|
||||
|
||||
abstract class <!CANNOT_WEAKEN_ACCESS_PRIVILEGE!>C<!> : I1(), I2
|
||||
|
||||
abstract class I3 {
|
||||
protected abstract fun foo(): Int
|
||||
}
|
||||
|
||||
interface I4 {
|
||||
fun foo(): Int
|
||||
}
|
||||
|
||||
abstract class B : I3(), I4
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// ISSUE: KT-66046
|
||||
|
||||
abstract class I1 {
|
||||
|
||||
Reference in New Issue
Block a user