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:
committed by
Space Team
parent
0ed6256bcc
commit
299d279915
@@ -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
|
||||
|
||||
Vendored
+20
-20
@@ -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<!>) {}
|
||||
|
||||
Vendored
+6
-6
@@ -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!>!!<!>
|
||||
""
|
||||
|
||||
-19
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user