K2 resolve: prefer derived class property to base class field
#KT-50082 Fixed
This commit is contained in:
committed by
teamcity
parent
642bbd38ba
commit
59bafedd8a
+34
@@ -3407,6 +3407,12 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntryFieldShadow.kt")
|
||||
public void testEnumEntryFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/enumEntryFieldShadow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
@@ -3568,6 +3574,34 @@ public class DiagnosisCompilerFirTestdataTestGenerated extends AbstractDiagnosis
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/propertyVsField")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class PropertyVsField {
|
||||
@Test
|
||||
public void testAllFilesPresentInPropertyVsField() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/propertyVsField"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fieldPropertyShadow.kt")
|
||||
public void testFieldPropertyShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/fieldPropertyShadow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyAndTwoFields.kt")
|
||||
public void testPropertyAndTwoFields() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyAndTwoFields.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyFieldShadow.kt")
|
||||
public void testPropertyFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyFieldShadow.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/references")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+33
@@ -3005,6 +3005,11 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("enumEntryFieldShadow.kt")
|
||||
public void testEnumEntryFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/enumEntryFieldShadow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/expectConstructor.kt");
|
||||
@@ -3144,6 +3149,34 @@ public class LazyBodyIsNotTouchedTilContractsPhaseTestGenerated extends Abstract
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/propertyVsField")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class PropertyVsField extends AbstractLazyBodyIsNotTouchedTilContractsPhaseTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInPropertyVsField() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/propertyVsField"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@TestMetadata("fieldPropertyShadow.kt")
|
||||
public void testFieldPropertyShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/fieldPropertyShadow.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyAndTwoFields.kt")
|
||||
public void testPropertyAndTwoFields() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyAndTwoFields.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("propertyFieldShadow.kt")
|
||||
public void testPropertyFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyFieldShadow.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/references")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
FILE: DerivedEnum.kt
|
||||
public final enum class DerivedEnum : R|BaseJava|, R|kotlin/Enum<DerivedEnum>| {
|
||||
private constructor(): R|DerivedEnum| {
|
||||
super<R|kotlin/Enum<DerivedEnum>|>()
|
||||
}
|
||||
|
||||
public final static enum entry x: R|DerivedEnum|
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
R|/bar|(R|/DerivedEnum.x|)
|
||||
R|/baz|(<Unresolved name: y>#)
|
||||
R|/baz|(Q|BaseJava|.R|/BaseJava.y|)
|
||||
}
|
||||
|
||||
public final static fun values(): R|kotlin/Array<DerivedEnum>| {
|
||||
}
|
||||
|
||||
public final static fun valueOf(value: R|kotlin/String|): R|DerivedEnum| {
|
||||
}
|
||||
|
||||
public final static val entries: R|kotlin/enums/EnumEntries<DerivedEnum>|
|
||||
public get(): R|kotlin/enums/EnumEntries<DerivedEnum>|
|
||||
|
||||
}
|
||||
public final fun bar(e: R|DerivedEnum|): R|kotlin/Unit| {
|
||||
}
|
||||
public final fun baz(s: R|kotlin/String|): R|kotlin/Unit| {
|
||||
Q|DerivedEnum|.R|/DerivedEnum.x|
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// FILE: BaseJava.java
|
||||
|
||||
public interface BaseJava {
|
||||
String x = "";
|
||||
String y = "";
|
||||
}
|
||||
|
||||
// FILE: DerivedEnum.kt
|
||||
|
||||
enum class DerivedEnum : BaseJava {
|
||||
x;
|
||||
|
||||
fun foo() {
|
||||
bar(x)
|
||||
baz(<!UNRESOLVED_REFERENCE!>y<!>)
|
||||
baz(BaseJava.y)
|
||||
}
|
||||
}
|
||||
|
||||
fun bar(e: DerivedEnum) {}
|
||||
|
||||
fun baz(s: String) {
|
||||
DerivedEnum.x
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
FILE: KotlinBase.kt
|
||||
public open class KotlinBase : R|kotlin/Any| {
|
||||
public constructor(): R|KotlinBase| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val abcd: R|kotlin/String| = String(abcd)
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
FILE: KotlinProxy.kt
|
||||
public abstract interface KotlinProxy : R|kotlin/Any| {
|
||||
public open val zyxw: R|kotlin/String|
|
||||
public get(): R|kotlin/String| {
|
||||
^ String(zyxw)
|
||||
}
|
||||
|
||||
}
|
||||
FILE: test.kt
|
||||
public final class Derived : R|Test|, R|KotlinProxy| {
|
||||
public constructor(): R|Derived| {
|
||||
super<R|Test|>()
|
||||
}
|
||||
|
||||
public final fun test(): R|kotlin/Unit| {
|
||||
this@R|/Derived|.R|/Test.abcd|
|
||||
this@R|/Derived|.R|/Test.zyxw|
|
||||
}
|
||||
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// FILE: Test.java
|
||||
|
||||
public class Test extends KotlinBase {
|
||||
public final String abcd = "ABCD";
|
||||
|
||||
public final String zyxw = "ZYXW";
|
||||
}
|
||||
|
||||
// FILE: KotlinBase.kt
|
||||
|
||||
open class KotlinBase {
|
||||
val abcd = "abcd"
|
||||
}
|
||||
|
||||
// FILE: KotlinProxy.kt
|
||||
|
||||
interface KotlinProxy {
|
||||
val zyxw get() = "zyxw"
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
class Derived : Test(), KotlinProxy {
|
||||
fun test() {
|
||||
abcd // field!
|
||||
zyxw // field!
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
FILE: KotlinBase.kt
|
||||
public open class KotlinBase : R|kotlin/Any| {
|
||||
public constructor(): R|KotlinBase| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public final val abcd: R|kotlin/String| = String(abcd)
|
||||
public get(): R|kotlin/String|
|
||||
|
||||
}
|
||||
FILE: test.kt
|
||||
public final fun test(d: R|JavaDerived|): R|kotlin/Unit| {
|
||||
R|<local>/d|.R|/JavaDerived.abcd|
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// FILE: Test.java
|
||||
|
||||
public class Test extends KotlinBase {
|
||||
public final String abcd = "ABCD";
|
||||
}
|
||||
|
||||
// FILE: KotlinBase.kt
|
||||
|
||||
open class KotlinBase {
|
||||
val abcd = "abcd"
|
||||
}
|
||||
|
||||
// FILE: JavaDerived.java
|
||||
|
||||
public class JavaDerived extends Test {
|
||||
public final String abcd = "AaBbCcDd"
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
fun test(d: JavaDerived) {
|
||||
d.abcd // JavaDerived
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
FILE: test.kt
|
||||
public final class Test2 : R|Test| {
|
||||
public constructor(): R|Test2| {
|
||||
super<R|Test|>()
|
||||
}
|
||||
|
||||
private final val text: R|kotlin/String| = String(BCDE)
|
||||
private get(): R|kotlin/String|
|
||||
|
||||
private final val publicPrivateText: R|kotlin/String| = String(YXWV)
|
||||
private get(): R|kotlin/String|
|
||||
|
||||
public final fun check(): R|kotlin/String| {
|
||||
^check this@R|/Test2|.R|/Test2.text|
|
||||
}
|
||||
|
||||
}
|
||||
public final fun check(): R|kotlin/String!| {
|
||||
^check R|/Test2.Test2|().R|/Test.publicPrivateText|
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
// FILE: Test.java
|
||||
|
||||
public class Test {
|
||||
protected final String text = "ABCD";
|
||||
|
||||
public final String publicPrivateText = "ZYXW";
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
class Test2 : Test() {
|
||||
private val text = "BCDE"
|
||||
|
||||
private val publicPrivateText = "YXWV"
|
||||
|
||||
fun check() = text // Should be resolved to Test2.text, not to Test.text
|
||||
}
|
||||
|
||||
fun check() = Test2().publicPrivateText // Should be resolved to Test.publicPrivateText (Test2 member is private)
|
||||
|
||||
+34
@@ -3407,6 +3407,12 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntryFieldShadow.kt")
|
||||
public void testEnumEntryFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/enumEntryFieldShadow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
@@ -3568,6 +3574,34 @@ public class FirDiagnosticTestGenerated extends AbstractFirDiagnosticTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/propertyVsField")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class PropertyVsField {
|
||||
@Test
|
||||
public void testAllFilesPresentInPropertyVsField() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/propertyVsField"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fieldPropertyShadow.kt")
|
||||
public void testFieldPropertyShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/fieldPropertyShadow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyAndTwoFields.kt")
|
||||
public void testPropertyAndTwoFields() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyAndTwoFields.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyFieldShadow.kt")
|
||||
public void testPropertyFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyFieldShadow.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/references")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+34
@@ -3407,6 +3407,12 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/emptySelectorInQualifiedExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("enumEntryFieldShadow.kt")
|
||||
public void testEnumEntryFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/problems/enumEntryFieldShadow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("expectConstructor.kt")
|
||||
public void testExpectConstructor() throws Exception {
|
||||
@@ -3568,6 +3574,34 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/propertyVsField")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class PropertyVsField {
|
||||
@Test
|
||||
public void testAllFilesPresentInPropertyVsField() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/fir/analysis-tests/testData/resolve/propertyVsField"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("fieldPropertyShadow.kt")
|
||||
public void testFieldPropertyShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/fieldPropertyShadow.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyAndTwoFields.kt")
|
||||
public void testPropertyAndTwoFields() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyAndTwoFields.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("propertyFieldShadow.kt")
|
||||
public void testPropertyFieldShadow() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/propertyVsField/propertyFieldShadow.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/fir/analysis-tests/testData/resolve/references")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+53
-14
@@ -10,11 +10,12 @@ import org.jetbrains.kotlin.fir.containingClassLookupTag
|
||||
import org.jetbrains.kotlin.fir.declarations.FirField
|
||||
import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.resolve.BodyResolveComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.*
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.AbstractConeCallConflictResolver
|
||||
import org.jetbrains.kotlin.fir.resolve.calls.Candidate
|
||||
import org.jetbrains.kotlin.fir.resolve.inference.InferenceComponents
|
||||
import org.jetbrains.kotlin.fir.resolve.transformers.body.resolve.FirAbstractBodyResolveTransformer
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
|
||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||
|
||||
class JvmPlatformOverloadsConflictResolver(
|
||||
@@ -31,21 +32,59 @@ class JvmPlatformOverloadsConflictResolver(
|
||||
return candidates
|
||||
}
|
||||
val result = mutableSetOf<Candidate>()
|
||||
outerLoop@ for (myCandidate in candidates) {
|
||||
val me = myCandidate.symbol.fir
|
||||
if (me is FirProperty && me.symbol.containingClassLookupTag() != null) {
|
||||
for (otherCandidate in candidates) {
|
||||
val other = otherCandidate.symbol.fir
|
||||
if (other is FirField && other.symbol.containingClassLookupTag() != null) {
|
||||
// NB: FE 1.0 does class equivalence check here
|
||||
// However, in FIR container classes aren't the same for our samples (see fieldPropertyOverloads.kt)
|
||||
// E.g. we can have SomeConcreteJavaEnum for field and kotlin.Enum for static property 'name'
|
||||
continue@outerLoop
|
||||
}
|
||||
for (myCandidate in candidates) {
|
||||
when (val me = myCandidate.symbol.fir) {
|
||||
is FirProperty -> if (!me.isShadowedByFieldCandidate(candidates)) {
|
||||
result += myCandidate
|
||||
}
|
||||
is FirField -> if (!me.isShadowedByPropertyCandidate(candidates)) {
|
||||
result += myCandidate
|
||||
}
|
||||
else -> result += myCandidate
|
||||
}
|
||||
result += myCandidate
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun FirProperty.isShadowedByFieldCandidate(candidates: Set<Candidate>): Boolean {
|
||||
val propertyContainingClassLookupTag = unwrapFakeOverrides().symbol.containingClassLookupTag() ?: return false
|
||||
for (otherCandidate in candidates) {
|
||||
val field = otherCandidate.symbol.fir as? FirField ?: continue
|
||||
val fieldContainingClassLookupTag = field.unwrapFakeOverrides().symbol.containingClassLookupTag()
|
||||
if (fieldContainingClassLookupTag != null &&
|
||||
!propertyContainingClassLookupTag.strictlyDerivedFrom(fieldContainingClassLookupTag)
|
||||
) {
|
||||
// NB: FE 1.0 does class equivalence check here ^^^
|
||||
// However, in FIR container classes aren't the same for our samples (see fieldPropertyOverloads.kt)
|
||||
// E.g. we can have SomeConcreteJavaEnum for field and kotlin.Enum for static property 'name'
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun FirField.isShadowedByPropertyCandidate(candidates: Set<Candidate>): Boolean {
|
||||
val fieldContainingClassLookupTag = unwrapFakeOverrides().symbol.containingClassLookupTag() ?: return false
|
||||
for (otherCandidate in candidates) {
|
||||
val property = otherCandidate.symbol.fir as? FirProperty ?: continue
|
||||
val propertyContainingClassLookupTag = property.unwrapFakeOverrides().symbol.containingClassLookupTag()
|
||||
if (propertyContainingClassLookupTag != null &&
|
||||
propertyContainingClassLookupTag.strictlyDerivedFrom(fieldContainingClassLookupTag)
|
||||
) {
|
||||
// NB: FE 1.0 does class equivalence check here ^^^
|
||||
// However, in FIR container classes aren't the same for our samples (see fieldPropertyOverloads.kt)
|
||||
// E.g. we can have SomeConcreteJavaEnum for field and kotlin.Enum for static property 'name'
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun ConeClassLikeLookupTag.strictlyDerivedFrom(other: ConeClassLikeLookupTag): Boolean {
|
||||
if (this == other) return false
|
||||
val session = inferenceComponents.session
|
||||
val thisClass = this.toFirRegularClassSymbol(session)?.fir ?: return false
|
||||
|
||||
return thisClass.isSubclassOf(other, session, isStrict = true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
if (isStatic && containingClass != null) {
|
||||
containingUseSiteDeclarations.firstNotNullOfOrNull {
|
||||
if (it !is FirClass) return@firstNotNullOfOrNull null
|
||||
it.takeIf { it.isSubClass(containingLookupTag, session, supertypeSupplier) }
|
||||
it.takeIf { it.isSubclassOf(containingLookupTag, session, isStrict = false, supertypeSupplier) }
|
||||
}?.let { return it }
|
||||
}
|
||||
|
||||
@@ -380,10 +380,6 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
return false
|
||||
}
|
||||
|
||||
// 'local' isn't taken into account here
|
||||
private fun ClassId.isSame(other: ClassId): Boolean =
|
||||
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
|
||||
|
||||
private fun ConeClassLikeLookupTag.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? {
|
||||
if (classId.isLocal) return null
|
||||
val outerClassId = classId.outerClassId ?: return null
|
||||
@@ -405,11 +401,11 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
supertypeSupplier: SupertypeSupplier
|
||||
): Boolean {
|
||||
dispatchReceiver?.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
|
||||
if (containingUseSiteClass.isSubClass(companionOwnerLookupTag, session, supertypeSupplier)) return true
|
||||
if (containingUseSiteClass.isSubclassOf(companionOwnerLookupTag, session, isStrict = false, supertypeSupplier)) return true
|
||||
}
|
||||
|
||||
return when {
|
||||
!containingUseSiteClass.isSubClass(ownerLookupTag, session, supertypeSupplier) -> false
|
||||
!containingUseSiteClass.isSubclassOf(ownerLookupTag, session, isStrict = false, supertypeSupplier) -> false
|
||||
isVariableOrNamedFunction -> doesReceiverFitForProtectedVisibility(
|
||||
dispatchReceiver,
|
||||
containingUseSiteClass,
|
||||
@@ -460,26 +456,6 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun FirClass.isSubClass(
|
||||
ownerLookupTag: ConeClassLikeLookupTag,
|
||||
session: FirSession,
|
||||
supertypeSupplier: SupertypeSupplier
|
||||
): Boolean {
|
||||
if (classId.isSame(ownerLookupTag.classId)) return true
|
||||
|
||||
return lookupSuperTypes(
|
||||
this,
|
||||
lookupInterfaces = true,
|
||||
deep = true,
|
||||
session,
|
||||
substituteTypes = false,
|
||||
supertypeSupplier
|
||||
).any { superType ->
|
||||
// Note: We check just classId here, so type substitution isn't needed ^ (we aren't interested in type arguments)
|
||||
(superType as? ConeClassLikeType)?.fullyExpandedType(session)?.lookupTag?.classId?.isSame(ownerLookupTag.classId) == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun ReceiverValue?.ownerIfCompanion(session: FirSession): ConeClassLikeLookupTag? =
|
||||
(this?.type as? ConeClassLikeType)?.lookupTag?.ownerIfCompanion(session)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.resolve
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.classId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.expandedConeType
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
|
||||
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.types.model.CaptureStatus
|
||||
import org.jetbrains.kotlin.utils.SmartList
|
||||
import org.jetbrains.kotlin.utils.SmartSet
|
||||
@@ -90,6 +92,33 @@ fun lookupSuperTypes(
|
||||
}
|
||||
}
|
||||
|
||||
fun FirClass.isSubclassOf(
|
||||
ownerLookupTag: ConeClassLikeLookupTag,
|
||||
session: FirSession,
|
||||
isStrict: Boolean,
|
||||
supertypeSupplier: SupertypeSupplier = SupertypeSupplier.Default
|
||||
): Boolean {
|
||||
if (classId.isSame(ownerLookupTag.classId)) {
|
||||
return !isStrict
|
||||
}
|
||||
|
||||
return lookupSuperTypes(
|
||||
this,
|
||||
lookupInterfaces = true,
|
||||
deep = true,
|
||||
session,
|
||||
substituteTypes = false,
|
||||
supertypeSupplier
|
||||
).any { superType ->
|
||||
// Note: We check just classId here, so type substitution isn't needed
|
||||
superType.lookupTag.classId.isSame(ownerLookupTag.classId)
|
||||
}
|
||||
}
|
||||
|
||||
// 'local' isn't taken into account here
|
||||
fun ClassId.isSame(other: ClassId): Boolean =
|
||||
packageFqName == other.packageFqName && relativeClassName == other.relativeClassName
|
||||
|
||||
fun FirClass.isThereLoopInSupertypes(session: FirSession): Boolean {
|
||||
val visitedSymbols: MutableSet<FirClassifierSymbol<*>> = SmartSet.create()
|
||||
val inProcess: MutableSet<FirClassifierSymbol<*>> = mutableSetOf()
|
||||
|
||||
Reference in New Issue
Block a user