K2: Fix false-negative RETURN_TYPE_MISMATCH
^KT-53987 Fixed ^KT-55932 Fixed
This commit is contained in:
committed by
Space Team
parent
d7399ed1cf
commit
9fa0f51a61
Vendored
+1
-1
@@ -180,7 +180,7 @@ FILE: returnTypeMismatchOnOverride.kt
|
||||
}
|
||||
|
||||
public open fun kek(): R|Z| {
|
||||
^kek R|/Z.Z<CS errors: /Z.Z>#|()
|
||||
^kek R|/Z.Z|()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
FILE: mutableList.kt
|
||||
public final fun foo(): R|kotlin/Unit| {
|
||||
lvar listVar: R|kotlin/collections/MutableList<kotlin/Int>| = R|kotlin/collections/mutableListOf|<R|kotlin/Int|>(vararg(Int(1), Int(2), Int(3)))
|
||||
R|<local>/listVar| = R|<local>/listVar|.R|kotlin/collections/plus<CS errors: kotlin/collections/plus>#|<R|kotlin/Int|>(Int(4))
|
||||
R|<local>/listVar| = R|<local>/listVar|.R|kotlin/collections/plus|<R|kotlin/Int|>(Int(4))
|
||||
}
|
||||
|
||||
+1
-2
@@ -2,7 +2,6 @@ fun <T> bar(): T {
|
||||
return null <!UNCHECKED_CAST!>as T<!>
|
||||
}
|
||||
|
||||
class X() : <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>B<!> by <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!><!VARIABLE_EXPECTED!><!UNRESOLVED_REFERENCE!>get<!>()<!> = bar()<!> {
|
||||
class X() : <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>B<!> by <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!><!VARIABLE_EXPECTED!><!UNRESOLVED_REFERENCE!>get<!>()<!> = <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar<!>()<!> {
|
||||
val prop = <!ASSIGNMENT_IN_EXPRESSION_CONTEXT!><!VARIABLE_EXPECTED!><!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>bar<!>()<!> = 2<!>
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ FILE: basic.kt
|
||||
^okOneLineFunction Int(10).R|kotlin/Int.plus|(Int(1))
|
||||
}
|
||||
public final fun errorOneLineFunction(): R|kotlin/String| {
|
||||
^errorOneLineFunction Int(10).R|kotlin/Int.plus<CS errors: kotlin/Int.plus>#|(Int(1))
|
||||
^errorOneLineFunction Int(10).R|kotlin/Int.plus|(Int(1))
|
||||
}
|
||||
public final class A : R|kotlin/Any| {
|
||||
public constructor(): R|A| {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
// bug: type of the expression in return statement is Char
|
||||
fun illegalReturnIf(): Char {
|
||||
return if (1 < 2) 'a' else { 1 }
|
||||
return <!RETURN_TYPE_MISMATCH!>if (1 < 2) 'a' else { 1 }<!>
|
||||
}
|
||||
|
||||
fun foo(): String {
|
||||
|
||||
+6
@@ -6566,6 +6566,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/improperElseInExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incorrectElvis.kt")
|
||||
public void testIncorrectElvis() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/incorrectElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jumpAcrossFunctionBoundary.kt")
|
||||
public void testJumpAcrossFunctionBoundary() throws Exception {
|
||||
|
||||
+6
@@ -6560,6 +6560,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/improperElseInExpression.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("incorrectElvis.kt")
|
||||
public void testIncorrectElvis() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/controlStructures/incorrectElvis.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("jumpAcrossFunctionBoundary.kt")
|
||||
public void testJumpAcrossFunctionBoundary() throws Exception {
|
||||
|
||||
-4
@@ -379,10 +379,6 @@ private fun ConstraintSystemError.toDiagnostic(
|
||||
|
||||
when (position) {
|
||||
is ConeExpectedTypeConstraintPosition -> {
|
||||
if (position.expectedTypeMismatchIsReportedInChecker) {
|
||||
errorsToIgnore.add(this)
|
||||
return null
|
||||
}
|
||||
val inferredType =
|
||||
if (!lowerConeType.isNullableNothing)
|
||||
lowerConeType
|
||||
|
||||
+12
-7
@@ -166,30 +166,35 @@ class FirCallCompleter(
|
||||
mayBeCoercionToUnitApplied: Boolean
|
||||
) {
|
||||
val expectedType = expectedTypeRef?.coneTypeSafe<ConeKotlinType>() ?: return
|
||||
val expectedTypeConstraintPosition = ConeExpectedTypeConstraintPosition(expectedTypeMismatchIsReportedInChecker)
|
||||
|
||||
val system = candidate.system
|
||||
when {
|
||||
!shouldEnforceExpectedType -> {
|
||||
system.addSubtypeConstraintIfCompatible(initialType, expectedType, expectedTypeConstraintPosition)
|
||||
// If type mismatch is assumed to be reported in the checker, we should not add a subtyping constraint that leads to error.
|
||||
// Because it might make resulting type correct while, it's hopefully would be more clear if we let the call be inferred without
|
||||
// the expected type, and then would report diagnostic in the checker.
|
||||
// It's assumed to be safe & sound, because if constraint system has contradictions when expected type is added,
|
||||
// the resulting expression type cannot be inferred to something that is a subtype of `expectedType`,
|
||||
// thus the diagnostic should be reported.
|
||||
!shouldEnforceExpectedType || expectedTypeMismatchIsReportedInChecker -> {
|
||||
system.addSubtypeConstraintIfCompatible(initialType, expectedType, ConeExpectedTypeConstraintPosition)
|
||||
}
|
||||
isFromCast -> {
|
||||
if (candidate.isFunctionForExpectTypeFromCastFeature()) {
|
||||
system.addSubtypeConstraint(
|
||||
initialType, expectedType,
|
||||
ConeExpectedTypeConstraintPosition(expectedTypeMismatchIsReportedInChecker = false),
|
||||
ConeExpectedTypeConstraintPosition,
|
||||
)
|
||||
}
|
||||
}
|
||||
!expectedType.isUnitOrFlexibleUnit || (!mayBeCoercionToUnitApplied && !expectedTypeMismatchIsReportedInChecker) -> {
|
||||
system.addSubtypeConstraint(initialType, expectedType, expectedTypeConstraintPosition)
|
||||
system.addSubtypeConstraint(initialType, expectedType, ConeExpectedTypeConstraintPosition)
|
||||
}
|
||||
system.notFixedTypeVariables.isEmpty() -> return
|
||||
expectedType.isUnit -> {
|
||||
system.addEqualityConstraintIfCompatible(initialType, expectedType, expectedTypeConstraintPosition)
|
||||
system.addEqualityConstraintIfCompatible(initialType, expectedType, ConeExpectedTypeConstraintPosition)
|
||||
}
|
||||
else -> {
|
||||
system.addSubtypeConstraintIfCompatible(initialType, expectedType, expectedTypeConstraintPosition)
|
||||
system.addSubtypeConstraintIfCompatible(initialType, expectedType, ConeExpectedTypeConstraintPosition)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -18,9 +18,7 @@ class ConeFixVariableConstraintPosition(variable: TypeVariableMarker) : FixVaria
|
||||
|
||||
class ConeArgumentConstraintPosition(argument: FirElement) : ArgumentConstraintPosition<FirElement>(argument)
|
||||
|
||||
class ConeExpectedTypeConstraintPosition(
|
||||
val expectedTypeMismatchIsReportedInChecker: Boolean
|
||||
) : ExpectedTypeConstraintPosition<Nothing?>(null)
|
||||
object ConeExpectedTypeConstraintPosition : ExpectedTypeConstraintPosition<Nothing?>(null)
|
||||
|
||||
class ConeExplicitTypeParameterConstraintPosition(
|
||||
typeArgument: FirTypeProjection,
|
||||
|
||||
Reference in New Issue
Block a user