K2: Don't report BUILDER_INFERENCE_STUB_RECEIVER for members of Any

This commit actually does two things:
- Adds Any scope to stub type
- Makes CheckDispatchReceiver treat stub types
as non-null for the unsafe call check to make such candidates viable

Related to KT-59369
This commit is contained in:
Simon Ogorodnik
2023-11-29 10:13:13 +01:00
committed by Space Team
parent 0ed6256bcc
commit 299d279915
6 changed files with 55 additions and 47 deletions
@@ -91,7 +91,25 @@ private fun ConeKotlinType.scope(
intersectionType.scope(useSiteSession, scopeSession, requiredMembersPhase) ?: FirTypeScope.Empty
}
}
is ConeStubTypeForChainInference -> {
// Actually, it should be the intersection of bounds, but K1 doesn't think so.
// interface ABC {
// fun foo()
// }
//
// class Buildee<out U : ABC> {
// fun get(): U = null!!
// }
//
// fun <F: ABC> buildsome(l: Buildee<F>.() -> Unit) {}
//
// fun test() {
// buildsome {
// this.get().foo()
// }
// }
useSiteSession.builtinTypes.anyType.type.scope(useSiteSession, scopeSession, requiredMembersPhase)
}
is ConeRawType -> lowerBound.scope(useSiteSession, scopeSession, requiredMembersPhase)
is ConeDynamicType -> useSiteSession.dynamicMembersStorage.getDynamicScopeFor(scopeSession)
is ConeFlexibleType -> lowerBound.scope(useSiteSession, scopeSession, requiredMembersPhase)
@@ -184,7 +184,15 @@ object CheckDispatchReceiver : ResolutionStage() {
}
val dispatchReceiverValueType = candidate.dispatchReceiver?.resolvedType ?: return
val isReceiverNullable = !AbstractNullabilityChecker.isSubtypeOfAny(context.session.typeContext, dispatchReceiverValueType)
// TODO: Actually, we should treat stub types as non-nullable for the isReceiverNullable check
// Otherwise, we won't able to resolve to member toString/hashCode due to UnsafeCall error
// It was possible in K1, due to the fact that K1 doesn't use AbstractNullabilityChecker directly
// But, AbstractNullabilityChecker.isSubtypeOfAny doesn't respect stubTypeEqualToAnything
val isStubType = dispatchReceiverValueType is ConeStubTypeForChainInference
val isReceiverNullable =
!AbstractNullabilityChecker.isSubtypeOfAny(context.session.typeContext, dispatchReceiverValueType) && !isStubType
val isCandidateFromUnstableSmartcast =
(candidate.originScope as? FirUnstableSmartcastTypeScope)?.isSymbolFromUnstableSmartcast(candidate.symbol) == true
@@ -23,10 +23,10 @@ fun test() {
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get().test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.hashCode()<!>
get()?.<!NONE_APPLICABLE!>equals<!>(1)
get()?.hashCode()
get()?.equals(1)
// there is `String?.equals` extension
<!BUILDER_INFERENCE_STUB_RECEIVER!>get().equals("")<!>
get().equals("")
}
val ret2 = build {
emit(1)
@@ -34,12 +34,12 @@ fun test() {
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get().test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.hashCode()<!>
get()?.<!NONE_APPLICABLE!>equals<!>(1)
get()?.hashCode()
get()?.equals(1)
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x?.hashCode()<!>
x?.<!NONE_APPLICABLE!>equals<!>(1)
<!BUILDER_INFERENCE_STUB_RECEIVER!>x.equals("")<!>
x?.hashCode()
x?.equals(1)
x.equals("")
}
val ret3 = build {
emit(1)
@@ -47,11 +47,11 @@ fun test() {
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get().test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.hashCode()<!>
get()?.<!NONE_APPLICABLE!>equals<!>(1)
get()?.hashCode()
get()?.equals(1)
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x?.hashCode()<!>
x?.<!NONE_APPLICABLE!>equals<!>(1)
x?.hashCode()
x?.equals(1)
if (get() == null) {}
if (<!FORBIDDEN_IDENTITY_EQUALS_WARNING!>get() === null<!>) {}
@@ -163,11 +163,11 @@ fun test() {
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get().test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.hashCode()<!>
get()?.<!NONE_APPLICABLE!>equals<!>(1)
get()?.hashCode()
get()?.equals(1)
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x?.hashCode()<!>
x?.<!NONE_APPLICABLE!>equals<!>(1)
x?.hashCode()
x?.equals(1)
if (get() == null) {}
if (<!FORBIDDEN_IDENTITY_EQUALS_WARNING!>get() === null<!>) {}
@@ -293,11 +293,11 @@ fun test() {
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get().test2()<!>
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()?.hashCode()<!>
get()?.<!NONE_APPLICABLE!>equals<!>(1)
get()?.hashCode()
get()?.equals(1)
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x?.hashCode()<!>
x?.<!NONE_APPLICABLE!>equals<!>(1)
x?.hashCode()
x?.equals(1)
if (get() == null) {}
if (<!FORBIDDEN_IDENTITY_EQUALS_WARNING!>get() === null<!>) {}
@@ -25,27 +25,27 @@ fun <R1 : R2, R2> build4(x: R2, block: TestInterface<R1>.() -> Unit): R1 = TODO(
fun test(a: String?) {
val ret1 = build {
emit(1)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")<!>
get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")<!>
x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
x <!USELESS_ELVIS!>?: 1<!>
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
""
}
val ret2 = build2 {
emit(1)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")<!>
get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")<!>
x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
x <!USELESS_ELVIS!>?: 1<!>
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
""
}
val ret3 = build3 {
emit(1)
<!BUILDER_INFERENCE_STUB_RECEIVER!>get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")<!>
get()<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
val x = get()
<!BUILDER_INFERENCE_STUB_RECEIVER!>x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")<!>
x<!UNNECESSARY_SAFE_CALL!>?.<!>equals("")
x <!USELESS_ELVIS!>?: 1<!>
x<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>
""
@@ -1,19 +0,0 @@
// !OPT_IN: kotlin.RequiresOptIn
// !DIAGNOSTICS: -UNUSED_PARAMETER
import kotlin.experimental.ExperimentalTypeInference
class TypeDefinition<KotlinType : Any> {
fun parse(parser: (serializedValue: String) -> KotlinType?): Unit = TODO()
fun serialize(parser: (value: KotlinType) -> Any?): Unit = TODO()
}
@OptIn(ExperimentalTypeInference::class)
fun <KotlinType : Any> defineType(definition: TypeDefinition<KotlinType>.() -> Unit): Unit = TODO()
fun main() {
defineType {
parse { it.toInt() }
serialize { <!BUILDER_INFERENCE_STUB_RECEIVER!>it.toString()<!> }
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !OPT_IN: kotlin.RequiresOptIn
// !DIAGNOSTICS: -UNUSED_PARAMETER