[NI] Continue resolution after unstable smart cast on receiver

The old inference cosideres candidates with unstable smartcast on
receiver unsuccessful, therefore another one may be selected.
KT-36264
This commit is contained in:
Pavel Kirpichenkov
2020-02-11 17:53:11 +03:00
parent 4997c9535c
commit 15d744c3da
12 changed files with 126 additions and 10 deletions
@@ -18377,6 +18377,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
runTest("compiler/testData/diagnostics/tests/resolve/newLineLambda.kt");
}
@TestMetadata("noStopOnReceiverUnstableSmartCast.kt")
public void testNoStopOnReceiverUnstableSmartCast() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/noStopOnReceiverUnstableSmartCast.kt");
}
@TestMetadata("objectLiteralAsArgument.kt")
public void testObjectLiteralAsArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/objectLiteralAsArgument.kt");
@@ -571,8 +571,9 @@ class StateMachineBuilder(
override fun visitReturn(expression: IrReturn) {
expression.acceptChildrenVoid(this)
if (expression.returnTargetSymbol is IrReturnableBlockSymbol) {
val (exitState, varSymbol) = returnableBlockMap[expression.returnTargetSymbol]!!
val returnTarget = expression.returnTargetSymbol
if (returnTarget is IrReturnableBlockSymbol) {
val (exitState, varSymbol) = returnableBlockMap[returnTarget]!!
if (varSymbol != null) {
transformLastExpression { JsIrBuilder.buildSetVariable(varSymbol, it, it.type) }
}
@@ -64,7 +64,7 @@ private fun checkExpressionArgument(
): KotlinCallDiagnostic? {
if (unstableType != null) {
if (csBuilder.addSubtypeConstraintIfCompatible(unstableType, actualExpectedType, position)) {
return UnstableSmartCast(expressionArgument, unstableType)
return UnstableSmartCast(expressionArgument, unstableType, isReceiver)
}
}
@@ -112,7 +112,7 @@ private fun checkExpressionArgument(
val expectedNullableType = expectedType.makeNullableAsSpecified(true)
if (unstableType != null && csBuilder.addSubtypeConstraintIfCompatible(unstableType, expectedType, position)) {
diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType))
diagnosticsHolder.addDiagnostic(UnstableSmartCast(expressionArgument, unstableType, isReceiver))
} else if (csBuilder.addSubtypeConstraintIfCompatible(argumentType, expectedNullableType, position)) {
diagnosticsHolder.addDiagnostic(UnsafeCallError(expressionArgument))
} else {
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability
import org.jetbrains.kotlin.resolve.calls.tower.ResolutionCandidateApplicability.*
import org.jetbrains.kotlin.types.TypeConstructor
import org.jetbrains.kotlin.types.UnwrappedType
@@ -138,11 +139,23 @@ class SmartCastDiagnostic(
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
}
class UnstableSmartCast(
class UnstableSmartCast private constructor(
val argument: ExpressionKotlinCallArgument,
val targetType: UnwrappedType
) : KotlinCallDiagnostic(RESOLVED_WITH_ERROR) {
val targetType: UnwrappedType,
applicability: ResolutionCandidateApplicability,
) : KotlinCallDiagnostic(applicability) {
override fun report(reporter: DiagnosticReporter) = reporter.onCallArgument(argument, this)
companion object {
operator fun invoke(
argument: ExpressionKotlinCallArgument,
targetType: UnwrappedType,
isReceiver: Boolean = false,
): UnstableSmartCast {
val applicability = if (isReceiver) MAY_THROW_RUNTIME_ERROR else RESOLVED_WITH_ERROR
return UnstableSmartCast(argument, targetType, applicability)
}
}
}
class UnsafeCallError(val receiver: SimpleKotlinCallArgument) : KotlinCallDiagnostic(MAY_THROW_RUNTIME_ERROR) {
@@ -0,0 +1,27 @@
interface Base {
val parent: Base
}
class Derived : Base {
override val parent: Base
get() = TODO()
}
fun test(d: Derived) {
when {
d.parent is Derived -> d.parent.parent
}
}
fun Any?.take() {}
class Something {
var prop: String? = null
fun String.take() {}
fun test() {
if (prop is String) {
prop.take()
}
}
}
@@ -0,0 +1,27 @@
interface Base {
val parent: Base
}
class Derived : Base {
override val parent: Base
get() = TODO()
}
fun test(d: Derived) {
when {
d.parent is Derived -> d.parent.parent
}
}
fun Any?.take() {}
class Something {
var prop: String? = null
fun String.take() {}
fun test() {
if (prop is String) {
prop.take()
}
}
}
@@ -0,0 +1,29 @@
package
public fun test(/*0*/ d: Derived): kotlin.Unit
public fun kotlin.Any?.take(): kotlin.Unit
public interface Base {
public abstract val parent: Base
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Derived : Base {
public constructor Derived()
public open override /*1*/ val parent: Base
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Something {
public constructor Something()
public final var prop: kotlin.String?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public final fun test(): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final fun kotlin.String.take(): kotlin.Unit
}
@@ -18,7 +18,7 @@ fun foo(list: StringList, arg: Unstable) {
list.remove(arg.first)
if (arg.first?.isEmpty() ?: false) {
// Should be still resolved to extension, without smart cast or smart cast impossible
list.remove(<!OI;SMARTCAST_IMPOSSIBLE!>arg.first<!>)
list.remove(<!NI;SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>arg.first<!>)
}
}
@@ -36,6 +36,6 @@ fun bar(list: BooleanList, arg: UnstableBoolean) {
list.remove(arg.first)
if (arg.first ?: false) {
// Should be still resolved to extension, without smart cast or smart cast impossible
list.remove(<!OI;SMARTCAST_IMPOSSIBLE!>arg.first<!>)
list.remove(<!NI;SMARTCAST_IMPOSSIBLE, SMARTCAST_IMPOSSIBLE!>arg.first<!>)
}
}
@@ -1,3 +1,5 @@
// !WITH_NEW_INFERENCE
fun create(): Map<String, String> = null!!
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = null!!
@@ -1,3 +1,5 @@
// !WITH_NEW_INFERENCE
fun create(): Map<String, String> = null!!
operator fun <K, V> Map<K, V>.iterator(): Iterator<Map.Entry<K, V>> = null!!
@@ -13,7 +15,7 @@ class MyClass {
m = create()
// See KT-7428
for ((k, v) in <!SMARTCAST_IMPOSSIBLE!>m<!>)
res += (k.length + v.length)
res <!NI;OVERLOAD_RESOLUTION_AMBIGUITY!>+=<!> (<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>k<!>.<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>length<!> <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>+<!> <!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>v<!>.<!NI;DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>length<!>)
return res
}
}
@@ -18389,6 +18389,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
runTest("compiler/testData/diagnostics/tests/resolve/newLineLambda.kt");
}
@TestMetadata("noStopOnReceiverUnstableSmartCast.kt")
public void testNoStopOnReceiverUnstableSmartCast() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/noStopOnReceiverUnstableSmartCast.kt");
}
@TestMetadata("objectLiteralAsArgument.kt")
public void testObjectLiteralAsArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/objectLiteralAsArgument.kt");
@@ -18379,6 +18379,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
runTest("compiler/testData/diagnostics/tests/resolve/newLineLambda.kt");
}
@TestMetadata("noStopOnReceiverUnstableSmartCast.kt")
public void testNoStopOnReceiverUnstableSmartCast() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/noStopOnReceiverUnstableSmartCast.kt");
}
@TestMetadata("objectLiteralAsArgument.kt")
public void testObjectLiteralAsArgument() throws Exception {
runTest("compiler/testData/diagnostics/tests/resolve/objectLiteralAsArgument.kt");