[FIR] KT-39033: Fix generic property override detection
#KT-39033 Fixed
This commit is contained in:
+15
@@ -0,0 +1,15 @@
|
||||
abstract class A {
|
||||
open val <D> Inv<D>.phasedFir: D get() = TODO()
|
||||
}
|
||||
|
||||
abstract class B : A() {
|
||||
final override val <D> Inv<D>.phasedFir: D get() = TODO()
|
||||
}
|
||||
|
||||
abstract class Inv<E>
|
||||
|
||||
class C : B() {
|
||||
fun foo(x: Inv<String>) {
|
||||
x.phasedFir
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
FILE: genericReceiverPropertyOverride.kt
|
||||
public abstract class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
public open val <D> R|Inv<D>|.phasedFir: R|D|
|
||||
public get(): R|D| {
|
||||
^ R|kotlin/TODO|()
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class B : R|A| {
|
||||
public constructor(): R|B| {
|
||||
super<R|A|>()
|
||||
}
|
||||
|
||||
public final override val <D> R|Inv<D>|.phasedFir: R|D|
|
||||
public get(): R|D| {
|
||||
^ R|kotlin/TODO|()
|
||||
}
|
||||
|
||||
}
|
||||
public abstract class Inv<E> : R|kotlin/Any| {
|
||||
public constructor<E>(): R|Inv<E>| {
|
||||
super<R|kotlin/Any|>()
|
||||
}
|
||||
|
||||
}
|
||||
public final class C : R|B| {
|
||||
public constructor(): R|C| {
|
||||
super<R|B|>()
|
||||
}
|
||||
|
||||
public final fun foo(x: R|Inv<kotlin/String>|): R|kotlin/Unit| {
|
||||
(this@R|/C|, R|<local>/x|).R|/B.phasedFir|<R|kotlin/String|>
|
||||
}
|
||||
|
||||
}
|
||||
Generated
+5
@@ -193,6 +193,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/genericFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericReceiverPropertyOverride.kt")
|
||||
public void testGenericReceiverPropertyOverride() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/genericReceiverPropertyOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectSuperCall.kt")
|
||||
public void testIncorrectSuperCall() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt");
|
||||
|
||||
+5
@@ -193,6 +193,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/genericFunctions.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("genericReceiverPropertyOverride.kt")
|
||||
public void testGenericReceiverPropertyOverride() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/genericReceiverPropertyOverride.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("incorrectSuperCall.kt")
|
||||
public void testIncorrectSuperCall() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/incorrectSuperCall.kt");
|
||||
|
||||
+17
-8
@@ -5,8 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.scopes.impl
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.substitutorByMap
|
||||
import org.jetbrains.kotlin.fir.scopes.FirOverrideChecker
|
||||
@@ -17,15 +16,24 @@ abstract class FirAbstractOverrideChecker : FirOverrideChecker {
|
||||
|
||||
protected abstract fun isEqualTypes(candidateTypeRef: FirTypeRef, baseTypeRef: FirTypeRef, substitutor: ConeSubstitutor): Boolean
|
||||
|
||||
private fun isCompatibleTypeParameters(
|
||||
overrideCandidate: FirTypeParameterRef,
|
||||
baseDeclaration: FirTypeParameterRef,
|
||||
substitutor: ConeSubstitutor
|
||||
): Boolean {
|
||||
if (overrideCandidate.symbol == baseDeclaration.symbol) return true
|
||||
if (overrideCandidate !is FirTypeParameter || baseDeclaration !is FirTypeParameter) return false
|
||||
return overrideCandidate.bounds.zip(baseDeclaration.bounds).all { (aBound, bBound) -> isEqualTypes(aBound, bBound, substitutor) }
|
||||
}
|
||||
|
||||
protected fun getSubstitutorIfTypeParametersAreCompatible(
|
||||
overrideCandidate: FirSimpleFunction,
|
||||
baseDeclaration: FirSimpleFunction
|
||||
overrideCandidate: FirCallableMemberDeclaration<*>,
|
||||
baseDeclaration: FirCallableMemberDeclaration<*>
|
||||
): ConeSubstitutor? {
|
||||
val substitutor = buildSubstitutorForOverridesCheck(overrideCandidate, baseDeclaration) ?: return null
|
||||
if (!overrideCandidate.typeParameters.zip(baseDeclaration.typeParameters).all { (a, b) ->
|
||||
a.bounds.size == b.bounds.size && a.bounds.zip(b.bounds).all { (aBound, bBound) ->
|
||||
isEqualTypes(aBound, bBound, substitutor)
|
||||
}
|
||||
if (
|
||||
overrideCandidate.typeParameters.zip(baseDeclaration.typeParameters).any { (override, base) ->
|
||||
!isCompatibleTypeParameters(override, base, substitutor)
|
||||
}
|
||||
) return null
|
||||
return substitutor
|
||||
@@ -38,6 +46,7 @@ fun buildSubstitutorForOverridesCheck(
|
||||
): ConeSubstitutor? {
|
||||
if (overrideCandidate.typeParameters.size != baseDeclaration.typeParameters.size) return null
|
||||
|
||||
if (baseDeclaration.typeParameters.isEmpty()) return ConeSubstitutor.Empty
|
||||
val types = baseDeclaration.typeParameters.map {
|
||||
ConeTypeParameterTypeImpl(it.symbol.toLookupTag(), false)
|
||||
}
|
||||
|
||||
+5
-9
@@ -11,11 +11,7 @@ import org.jetbrains.kotlin.fir.declarations.FirProperty
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
||||
import org.jetbrains.kotlin.fir.types.ConeTypeContext
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.types.AbstractStrictEqualityTypeChecker.strictEqualTypes
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
|
||||
import org.jetbrains.kotlin.types.model.SimpleTypeMarker
|
||||
@@ -24,7 +20,7 @@ class FirStandardOverrideChecker(session: FirSession) : FirAbstractOverrideCheck
|
||||
|
||||
private val context: ConeTypeContext = session.typeContext
|
||||
|
||||
private fun isEqualTypes(candidateType: ConeKotlinType, baseType: ConeKotlinType, substitutor: ConeSubstitutor): Boolean{
|
||||
private fun isEqualTypes(candidateType: ConeKotlinType, baseType: ConeKotlinType, substitutor: ConeSubstitutor): Boolean {
|
||||
val substitutedCandidateType = substitutor.substituteOrSelf(candidateType)
|
||||
val substitutedBaseType = substitutor.substituteOrSelf(baseType)
|
||||
return with(context) {
|
||||
@@ -76,8 +72,8 @@ class FirStandardOverrideChecker(session: FirSession) : FirAbstractOverrideCheck
|
||||
overrideCandidate: FirCallableMemberDeclaration<*>,
|
||||
baseDeclaration: FirProperty
|
||||
): Boolean {
|
||||
// TODO: substitutor
|
||||
return overrideCandidate is FirProperty &&
|
||||
isEqualReceiverTypes(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, ConeSubstitutor.Empty)
|
||||
if (overrideCandidate !is FirProperty) return false
|
||||
val substitutor = getSubstitutorIfTypeParametersAreCompatible(overrideCandidate, baseDeclaration) ?: return false
|
||||
return isEqualReceiverTypes(overrideCandidate.receiverTypeRef, baseDeclaration.receiverTypeRef, substitutor)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user