K2: add explicit cast to Any for Any function calls on stub types
This commit solves a stub type inconsistency problem.
As a part of KT-59369 fix we decided (see commit 299d2799),
that ConeStubTypeForChainInference has a scope of Any,
so we can safely resolve only to equals/hashCode/toString.
However, later we can replace a stub type with some inferred type,
which can have its own equals/hashCode/toString implementation,
while the call still refers Any member.
In this situation FIR2IR decides that we are calling a fake override,
which is not true, in fact we are calling an overriding method.
This leads to a crash in Native backend.
To solve this situation, we provide an explicit cast of a dispatch
receiver with a stub type (ConeStubTypeForChainInference) to Any,
thus confirming directly we are calling Any method and nothing else.
#KT-63932 Fixed
This commit is contained in:
committed by
Space Team
parent
a0deaea8fe
commit
dbca7358af
+12
@@ -43265,6 +43265,18 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnReceiver.kt")
|
||||||
|
public void testStubCallOnReceiver() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnVariable.kt")
|
||||||
|
public void testStubCallOnVariable() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("suspendCallsWithErrors.kt")
|
@TestMetadata("suspendCallsWithErrors.kt")
|
||||||
public void testSuspendCallsWithErrors() throws Exception {
|
public void testSuspendCallsWithErrors() throws Exception {
|
||||||
|
|||||||
+12
@@ -43265,6 +43265,18 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnReceiver.kt")
|
||||||
|
public void testStubCallOnReceiver() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnVariable.kt")
|
||||||
|
public void testStubCallOnVariable() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("suspendCallsWithErrors.kt")
|
@TestMetadata("suspendCallsWithErrors.kt")
|
||||||
public void testSuspendCallsWithErrors() throws Exception {
|
public void testSuspendCallsWithErrors() throws Exception {
|
||||||
|
|||||||
+12
@@ -41067,6 +41067,18 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnReceiver.kt")
|
||||||
|
public void testStubCallOnReceiver() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnVariable.kt")
|
||||||
|
public void testStubCallOnVariable() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("suspendCallsWithErrors.kt")
|
@TestMetadata("suspendCallsWithErrors.kt")
|
||||||
public void testSuspendCallsWithErrors() throws Exception {
|
public void testSuspendCallsWithErrors() throws Exception {
|
||||||
|
|||||||
+12
@@ -41187,6 +41187,18 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnReceiver.kt")
|
||||||
|
public void testStubCallOnReceiver() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnVariable.kt")
|
||||||
|
public void testStubCallOnVariable() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("suspendCallsWithErrors.kt")
|
@TestMetadata("suspendCallsWithErrors.kt")
|
||||||
public void testSuspendCallsWithErrors() throws Exception {
|
public void testSuspendCallsWithErrors() throws Exception {
|
||||||
|
|||||||
@@ -13,8 +13,11 @@ import org.jetbrains.kotlin.fir.declarations.*
|
|||||||
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
import org.jetbrains.kotlin.fir.declarations.utils.isInner
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
import org.jetbrains.kotlin.fir.declarations.utils.isStatic
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirOperation
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
import org.jetbrains.kotlin.fir.expressions.FirSmartCastExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.buildUnaryArgumentList
|
||||||
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier
|
import org.jetbrains.kotlin.fir.expressions.builder.buildResolvedQualifier
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.builder.buildTypeOperatorCall
|
||||||
import org.jetbrains.kotlin.fir.resolve.*
|
import org.jetbrains.kotlin.fir.resolve.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.*
|
import org.jetbrains.kotlin.fir.resolve.calls.*
|
||||||
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
|
||||||
@@ -25,6 +28,7 @@ import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
|||||||
import org.jetbrains.kotlin.fir.symbols.impl.*
|
import org.jetbrains.kotlin.fir.symbols.impl.*
|
||||||
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
import org.jetbrains.kotlin.fir.types.impl.FirImplicitAnyTypeRef
|
||||||
import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry
|
import org.jetbrains.kotlin.fir.utils.exceptions.withConeTypeEntry
|
||||||
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.HidesMembers
|
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.HidesMembers
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||||
@@ -213,6 +217,15 @@ class MemberScopeTowerLevel(
|
|||||||
val dispatchReceiverToUse = when {
|
val dispatchReceiverToUse = when {
|
||||||
isFromOriginalTypeInPresenceOfSmartCast ->
|
isFromOriginalTypeInPresenceOfSmartCast ->
|
||||||
getOriginalReceiverExpressionIfStableSmartCast()
|
getOriginalReceiverExpressionIfStableSmartCast()
|
||||||
|
// For a chain inference stub in dispatch receiver, we have to provide an explicit cast to Any
|
||||||
|
// See KT-63932
|
||||||
|
dispatchReceiverValue.type is ConeStubTypeForChainInference -> buildTypeOperatorCall {
|
||||||
|
source = dispatchReceiverValue.receiverExpression.source?.fakeElement(KtFakeSourceElementKind.CastToAnyForStubTypes)
|
||||||
|
operation = FirOperation.AS
|
||||||
|
conversionTypeRef = FirImplicitAnyTypeRef(source)
|
||||||
|
argumentList = buildUnaryArgumentList(dispatchReceiverValue.receiverExpression)
|
||||||
|
coneTypeOrNull = session.builtinTypes.anyType.coneType
|
||||||
|
}
|
||||||
else -> dispatchReceiverValue.receiverExpression
|
else -> dispatchReceiverValue.receiverExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -291,6 +291,9 @@ sealed class KtFakeSourceElementKind(final override val shouldSkipErrorTypeRepor
|
|||||||
|
|
||||||
// When a lambda is converted to a SAM type, the expression is wrapped in an extra node
|
// When a lambda is converted to a SAM type, the expression is wrapped in an extra node
|
||||||
object SamConversion : KtFakeSourceElementKind()
|
object SamConversion : KtFakeSourceElementKind()
|
||||||
|
|
||||||
|
// For it.functionFromAny() calls on a stub type
|
||||||
|
object CastToAnyForStubTypes : KtFakeSourceElementKind()
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed class AbstractKtSourceElement {
|
sealed class AbstractKtSourceElement {
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
// WITH_STDLIB
|
// WITH_STDLIB
|
||||||
// IGNORE_BACKEND_K2: NATIVE
|
|
||||||
|
|
||||||
import kotlin.experimental.ExperimentalTypeInference
|
import kotlin.experimental.ExperimentalTypeInference
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ FILE: kt36220.kt
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.serialize: R|kotlin/Unit|>|(<L> = serialize@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Any?| <inline=NoInline> {
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.serialize: R|kotlin/Unit|>|(<L> = serialize@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Any?| <inline=NoInline> {
|
||||||
^ R|<local>/it|.R|kotlin/Any.toString|()
|
^ (R|<local>/it| as R|kotlin/Any|).R|kotlin/Any.toString|()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+44
@@ -0,0 +1,44 @@
|
|||||||
|
FILE: stubCallOnReceiver.kt
|
||||||
|
public final class TypeDefinition<KotlinType : R|kotlin/Any|> : R|kotlin/Any| {
|
||||||
|
public constructor<KotlinType : R|kotlin/Any|>(): R|TypeDefinition<KotlinType>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun parse(parser: R|(@R|kotlin/ParameterName|(name = String(serializedValue)) kotlin/String) -> KotlinType?|): R|kotlin/Unit| {
|
||||||
|
^parse R|kotlin/TODO|()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun serialize(parser: R|KotlinType.() -> kotlin/Any?|): R|kotlin/Unit| {
|
||||||
|
^serialize R|kotlin/TODO|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun <KotlinType : R|kotlin/Any|> defineType(definition: R|TypeDefinition<KotlinType>.() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||||
|
^defineType R|kotlin/TODO|()
|
||||||
|
}
|
||||||
|
public final fun foo(): R|kotlin/Unit| {
|
||||||
|
R|/defineType|<R|kotlin/Int|>(<L> = defineType@fun R|TypeDefinition<kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||||
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.parse: R|kotlin/Unit|>|(<L> = parse@fun <anonymous>(it: R|@R|kotlin/ParameterName|(name = String(serializedValue)) kotlin/String|): R|kotlin/Int?| <inline=NoInline> {
|
||||||
|
^ R|<local>/it|.R|kotlin/text/toInt|()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.serialize: R|kotlin/Unit|>|(<L> = serialize@fun R|kotlin/Int|.<anonymous>(): R|kotlin/Any?| <inline=NoInline> {
|
||||||
|
^ (this@R|special/anonymous| as R|kotlin/Any|).R|kotlin/Any.toString|()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
public final fun bar(): R|kotlin/Unit| {
|
||||||
|
R|/defineType|<R|kotlin/Int|>(<L> = defineType@fun R|TypeDefinition<kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||||
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.parse: R|kotlin/Unit|>|(<L> = parse@fun <anonymous>(it: R|@R|kotlin/ParameterName|(name = String(serializedValue)) kotlin/String|): R|kotlin/Int?| <inline=NoInline> {
|
||||||
|
^ R|<local>/it|.R|kotlin/text/toInt|()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.serialize: R|kotlin/Unit|>|(<L> = serialize@fun R|kotlin/Int|.<anonymous>(): R|kotlin/Any?| <inline=NoInline> {
|
||||||
|
^ (this@R|special/anonymous| as R|kotlin/Any|).R|kotlin/Any.toString|()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// FIR_DUMP
|
||||||
|
// Similar to kt36220.kt, but with receivers instead of it
|
||||||
|
|
||||||
|
class TypeDefinition<KotlinType : Any> {
|
||||||
|
fun parse(parser: (serializedValue: String) -> KotlinType?): Unit = TODO()
|
||||||
|
fun serialize(parser: KotlinType.() -> Any?): Unit = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <KotlinType : Any> defineType(definition: TypeDefinition<KotlinType>.() -> Unit): Unit = TODO()
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
defineType {
|
||||||
|
parse { it.toInt() }
|
||||||
|
serialize { toString() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bar() {
|
||||||
|
defineType {
|
||||||
|
parse { it.toInt() }
|
||||||
|
serialize { this.toString() }
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+32
@@ -0,0 +1,32 @@
|
|||||||
|
FILE: stubCallOnVariable.kt
|
||||||
|
public final class TypeDefinition<KotlinType : R|kotlin/Any|> : R|kotlin/Any| {
|
||||||
|
public constructor<KotlinType : R|kotlin/Any|>(): R|TypeDefinition<KotlinType>| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun parse(parser: R|(@R|kotlin/ParameterName|(name = String(serializedValue)) kotlin/String) -> KotlinType?|): R|kotlin/Unit| {
|
||||||
|
^parse R|kotlin/TODO|()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun serialize(parser: R|(@R|kotlin/ParameterName|(name = String(value)) KotlinType) -> kotlin/Any?|): R|kotlin/Unit| {
|
||||||
|
^serialize R|kotlin/TODO|()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final fun <KotlinType : R|kotlin/Any|> defineType(definition: R|TypeDefinition<KotlinType>.() -> kotlin/Unit|): R|kotlin/Unit| {
|
||||||
|
^defineType R|kotlin/TODO|()
|
||||||
|
}
|
||||||
|
public final fun main(): R|kotlin/Unit| {
|
||||||
|
R|/defineType|<R|kotlin/Int|>(<L> = defineType@fun R|TypeDefinition<kotlin/Int>|.<anonymous>(): R|kotlin/Unit| <inline=NoInline> {
|
||||||
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.parse: R|kotlin/Unit|>|(<L> = parse@fun <anonymous>(it: R|@R|kotlin/ParameterName|(name = String(serializedValue)) kotlin/String|): R|kotlin/Int?| <inline=NoInline> {
|
||||||
|
^ R|<local>/it|.R|kotlin/text/toInt|()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
this@R|special/anonymous|.R|SubstitutionOverride</TypeDefinition.serialize: R|kotlin/Unit|>|(<L> = serialize@fun <anonymous>(it: R|kotlin/Int|): R|kotlin/Any?| <inline=NoInline> {
|
||||||
|
lval i: R|kotlin/Int| = R|<local>/it|
|
||||||
|
^ (R|<local>/i| as R|kotlin/Any|).R|kotlin/Any.toString|()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// FIR_DUMP
|
||||||
|
|
||||||
|
class TypeDefinition<KotlinType : Any> {
|
||||||
|
fun parse(parser: (serializedValue: String) -> KotlinType?): Unit = TODO()
|
||||||
|
fun serialize(parser: (value: KotlinType) -> Any?): Unit = TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <KotlinType : Any> defineType(definition: TypeDefinition<KotlinType>.() -> Unit): Unit = TODO()
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
defineType {
|
||||||
|
parse { it.toInt() }
|
||||||
|
serialize {
|
||||||
|
val i = it
|
||||||
|
i.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+12
@@ -43265,6 +43265,18 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/simpleGenerator.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnReceiver.kt")
|
||||||
|
public void testStubCallOnReceiver() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnReceiver.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("stubCallOnVariable.kt")
|
||||||
|
public void testStubCallOnVariable() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/stubCallOnVariable.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("suspendCallsWithErrors.kt")
|
@TestMetadata("suspendCallsWithErrors.kt")
|
||||||
public void testSuspendCallsWithErrors() throws Exception {
|
public void testSuspendCallsWithErrors() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user