diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt index b97230fab98..9878b0f2b76 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/ScopeUtils.kt @@ -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 { + // fun get(): U = null!! + // } + // + // fun buildsome(l: Buildee.() -> 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) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt index 44ba991c95e..fb580bcdbc8 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/calls/ResolutionStages.kt @@ -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 diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/memberScope.fir.kt b/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/memberScope.fir.kt index 642ed838b47..c0b696939d5 100644 --- a/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/memberScope.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/memberScope.fir.kt @@ -23,10 +23,10 @@ fun test() { get()?.test() get()?.test2() get().test2() - get()?.hashCode() - get()?.equals(1) + get()?.hashCode() + get()?.equals(1) // there is `String?.equals` extension - get().equals("") + get().equals("") } val ret2 = build { emit(1) @@ -34,12 +34,12 @@ fun test() { get()?.test() get()?.test2() get().test2() - get()?.hashCode() - get()?.equals(1) + get()?.hashCode() + get()?.equals(1) val x = get() - x?.hashCode() - x?.equals(1) - x.equals("") + x?.hashCode() + x?.equals(1) + x.equals("") } val ret3 = build { emit(1) @@ -47,11 +47,11 @@ fun test() { get()?.test() get()?.test2() get().test2() - get()?.hashCode() - get()?.equals(1) + get()?.hashCode() + get()?.equals(1) val x = get() - x?.hashCode() - x?.equals(1) + x?.hashCode() + x?.equals(1) if (get() == null) {} if (get() === null) {} @@ -163,11 +163,11 @@ fun test() { get()?.test() get()?.test2() get().test2() - get()?.hashCode() - get()?.equals(1) + get()?.hashCode() + get()?.equals(1) val x = get() - x?.hashCode() - x?.equals(1) + x?.hashCode() + x?.equals(1) if (get() == null) {} if (get() === null) {} @@ -293,11 +293,11 @@ fun test() { get()?.test() get()?.test2() get().test2() - get()?.hashCode() - get()?.equals(1) + get()?.hashCode() + get()?.equals(1) val x = get() - x?.hashCode() - x?.equals(1) + x?.hashCode() + x?.equals(1) if (get() == null) {} if (get() === null) {} diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/nullability.fir.kt b/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/nullability.fir.kt index e9aafbd897e..133ad7932b0 100644 --- a/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/nullability.fir.kt +++ b/compiler/testData/diagnostics/tests/inference/builderInference/stubTypes/nullability.fir.kt @@ -25,27 +25,27 @@ fun build4(x: R2, block: TestInterface.() -> Unit): R1 = TODO( fun test(a: String?) { val ret1 = build { emit(1) - get()?.equals("") + get()?.equals("") val x = get() - x?.equals("") + x?.equals("") x ?: 1 x!! "" } val ret2 = build2 { emit(1) - get()?.equals("") + get()?.equals("") val x = get() - x?.equals("") + x?.equals("") x ?: 1 x!! "" } val ret3 = build3 { emit(1) - get()?.equals("") + get()?.equals("") val x = get() - x?.equals("") + x?.equals("") x ?: 1 x!! "" diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.fir.kt deleted file mode 100644 index 9a2164295e4..00000000000 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.fir.kt +++ /dev/null @@ -1,19 +0,0 @@ -// !OPT_IN: kotlin.RequiresOptIn -// !DIAGNOSTICS: -UNUSED_PARAMETER - -import kotlin.experimental.ExperimentalTypeInference - -class TypeDefinition { - fun parse(parser: (serializedValue: String) -> KotlinType?): Unit = TODO() - fun serialize(parser: (value: KotlinType) -> Any?): Unit = TODO() -} - -@OptIn(ExperimentalTypeInference::class) -fun defineType(definition: TypeDefinition.() -> Unit): Unit = TODO() - -fun main() { - defineType { - parse { it.toInt() } - serialize { it.toString() } - } -} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.kt index 0231124efeb..d73e674faea 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/kt36220.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !OPT_IN: kotlin.RequiresOptIn // !DIAGNOSTICS: -UNUSED_PARAMETER