FIR checker: fix condition for property type mismatch on override
This commit is contained in:
committed by
Dmitriy Novozhilov
parent
065d0c66ab
commit
266432a482
+2
-2
@@ -3,7 +3,7 @@ open class A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open class B : A {
|
open class B : A {
|
||||||
override var test: Double = 20.0
|
override var test: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>Double<!> = 20.0
|
||||||
}
|
}
|
||||||
|
|
||||||
class C() : A() {
|
class C() : A() {
|
||||||
@@ -15,7 +15,7 @@ open class D() : B() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class E<T : Double>(val value: T) : B() {
|
class E<T : Double>(val value: T) : B() {
|
||||||
override var test: T = value
|
override var test: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>T<!> = value
|
||||||
}
|
}
|
||||||
|
|
||||||
open class F<T : Number>(val value: T) {
|
open class F<T : Number>(val value: T) {
|
||||||
|
|||||||
+16
-8
@@ -61,13 +61,13 @@ object FirOverrideChecker : FirRegularClassChecker() {
|
|||||||
|
|
||||||
private fun ConeKotlinType.substituteAllTypeParameters(
|
private fun ConeKotlinType.substituteAllTypeParameters(
|
||||||
overrideDeclaration: FirCallableMemberDeclaration<*>,
|
overrideDeclaration: FirCallableMemberDeclaration<*>,
|
||||||
baseDeclarationSymbol: FirCallableSymbol<*>,
|
baseDeclaration: FirCallableDeclaration<*>,
|
||||||
): ConeKotlinType {
|
): ConeKotlinType {
|
||||||
if (overrideDeclaration.typeParameters.isEmpty()) {
|
if (overrideDeclaration.typeParameters.isEmpty()) {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
val parametersOwner = baseDeclarationSymbol.fir.safeAs<FirTypeParametersOwner>()
|
val parametersOwner = baseDeclaration.safeAs<FirTypeParametersOwner>()
|
||||||
?: return this
|
?: return this
|
||||||
|
|
||||||
val map = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
val map = mutableMapOf<FirTypeParameterSymbol, ConeKotlinType>()
|
||||||
@@ -130,27 +130,35 @@ object FirOverrideChecker : FirRegularClassChecker() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See [OverrideResolver#isReturnTypeOkForOverride]
|
||||||
private fun FirCallableMemberDeclaration<*>.checkReturnType(
|
private fun FirCallableMemberDeclaration<*>.checkReturnType(
|
||||||
overriddenSymbols: List<FirCallableSymbol<*>>,
|
overriddenSymbols: List<FirCallableSymbol<*>>,
|
||||||
typeCheckerContext: AbstractTypeCheckerContext,
|
typeCheckerContext: AbstractTypeCheckerContext,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
): FirMemberDeclaration? {
|
): FirMemberDeclaration? {
|
||||||
val returnType = returnTypeRef.safeAs<FirResolvedTypeRef>()?.type
|
val overridingReturnType = returnTypeRef.safeAs<FirResolvedTypeRef>()?.type
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
// Don't report *_ON_OVERRIDE diagnostics according to an error return type. That should be reported separately.
|
// Don't report *_ON_OVERRIDE diagnostics according to an error return type. That should be reported separately.
|
||||||
if (returnType is ConeKotlinErrorType) {
|
if (overridingReturnType is ConeKotlinErrorType) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
val bounds = overriddenSymbols.map { context.returnTypeCalculator.tryCalculateReturnType(it.fir).coneType.upperBoundIfFlexible() }
|
val bounds = overriddenSymbols.map { context.returnTypeCalculator.tryCalculateReturnType(it.fir).coneType.upperBoundIfFlexible() }
|
||||||
|
|
||||||
for (it in bounds.indices) {
|
for (it in bounds.indices) {
|
||||||
val restriction = bounds[it]
|
val overriddenDeclaration = overriddenSymbols[it].fir
|
||||||
.substituteAllTypeParameters(this, overriddenSymbols[it])
|
|
||||||
|
|
||||||
if (!AbstractTypeChecker.isSubtypeOf(typeCheckerContext, returnType, restriction)) {
|
val overriddenReturnType = bounds[it].substituteAllTypeParameters(this, overriddenDeclaration)
|
||||||
return overriddenSymbols[it].fir.safeAs()
|
|
||||||
|
val isReturnTypeOkForOverride =
|
||||||
|
if (overriddenDeclaration is FirProperty && overriddenDeclaration.isVar)
|
||||||
|
AbstractTypeChecker.equalTypes(typeCheckerContext, overridingReturnType, overriddenReturnType)
|
||||||
|
else
|
||||||
|
AbstractTypeChecker.isSubtypeOf(typeCheckerContext, overridingReturnType, overriddenReturnType)
|
||||||
|
|
||||||
|
if (!isReturnTypeOkForOverride) {
|
||||||
|
return overriddenDeclaration.safeAs()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
interface Super {
|
|
||||||
var v: CharSequence
|
|
||||||
val v2: CharSequence
|
|
||||||
}
|
|
||||||
|
|
||||||
class Sub: Super {
|
|
||||||
override var v: String = "fail"
|
|
||||||
override val v2: String = "ok"
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
interface Super {
|
interface Super {
|
||||||
var v: CharSequence
|
var v: CharSequence
|
||||||
val v2: CharSequence
|
val v2: CharSequence
|
||||||
|
|||||||
+2
-2
@@ -18,7 +18,7 @@ class Case1 : Base() {
|
|||||||
|
|
||||||
override val a: <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>Any?<!>
|
override val a: <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>Any?<!>
|
||||||
get() = TODO()
|
get() = TODO()
|
||||||
override var b: String
|
override var b: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>String<!>
|
||||||
get() = TODO()
|
get() = TODO()
|
||||||
set(value)
|
set(value)
|
||||||
{}
|
{}
|
||||||
@@ -29,7 +29,7 @@ class Case1 : Base() {
|
|||||||
* TESTCASE NUMBER: 2
|
* TESTCASE NUMBER: 2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Case2(override val a: String, override var b: String) : Base() {
|
class Case2(override val a: String, override var b: <!VAR_TYPE_MISMATCH_ON_OVERRIDE!>String<!>) : Base() {
|
||||||
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>CharSequence?<!> {
|
override fun foo(): <!RETURN_TYPE_MISMATCH_ON_OVERRIDE!>CharSequence?<!> {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user