[FIR] Fix ClassCastException when rendering ACTUAL_WITHOUT_EXPECT
#KT-57320
This commit is contained in:
committed by
Space Team
parent
3b09313192
commit
3b0c36da3f
+1
@@ -361,6 +361,7 @@ internal object FirToKtConversionCreator {
|
||||
FqName::class,
|
||||
ClassId::class,
|
||||
FirModuleData::class,
|
||||
ExpectActualCompatibility::class,
|
||||
ExpectActualCompatibility.Incompatible::class,
|
||||
DeprecationInfo::class,
|
||||
ApiVersion::class,
|
||||
|
||||
+4
-4
@@ -3215,8 +3215,8 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
NoActualForExpectImpl(
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||
firDiagnostic.b,
|
||||
firDiagnostic.c.mapKeys { (incompatible, _) ->
|
||||
incompatible
|
||||
firDiagnostic.c.mapKeys { (expectActualCompatibility, _) ->
|
||||
expectActualCompatibility
|
||||
}.mapValues { (_, collection) ->
|
||||
collection.map { firBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(firBasedSymbol)
|
||||
@@ -3229,8 +3229,8 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
add(FirErrors.ACTUAL_WITHOUT_EXPECT) { firDiagnostic ->
|
||||
ActualWithoutExpectImpl(
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||
firDiagnostic.b.mapKeys { (incompatible, _) ->
|
||||
incompatible
|
||||
firDiagnostic.b.mapKeys { (expectActualCompatibility, _) ->
|
||||
expectActualCompatibility
|
||||
}.mapValues { (_, collection) ->
|
||||
collection.map { firBasedSymbol ->
|
||||
firSymbolBuilder.buildSymbol(firBasedSymbol)
|
||||
|
||||
+3
-2
@@ -80,6 +80,7 @@ import org.jetbrains.kotlin.psi.KtWhenEntry
|
||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -2262,13 +2263,13 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = NoActualForExpect::class
|
||||
abstract val declaration: KtSymbol
|
||||
abstract val module: FirModuleData
|
||||
abstract val compatibility: Map<Incompatible<FirBasedSymbol<*>>, List<KtSymbol>>
|
||||
abstract val compatibility: Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<KtSymbol>>
|
||||
}
|
||||
|
||||
abstract class ActualWithoutExpect : KtFirDiagnostic<KtNamedDeclaration>() {
|
||||
override val diagnosticClass get() = ActualWithoutExpect::class
|
||||
abstract val declaration: KtSymbol
|
||||
abstract val compatibility: Map<Incompatible<FirBasedSymbol<*>>, List<KtSymbol>>
|
||||
abstract val compatibility: Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<KtSymbol>>
|
||||
}
|
||||
|
||||
abstract class AmbiguousActuals : KtFirDiagnostic<KtNamedDeclaration>() {
|
||||
|
||||
+3
-2
@@ -81,6 +81,7 @@ import org.jetbrains.kotlin.psi.KtWhenEntry
|
||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -2727,14 +2728,14 @@ internal class ExpectedFunctionSourceWithDefaultArgumentsNotFoundImpl(
|
||||
internal class NoActualForExpectImpl(
|
||||
override val declaration: KtSymbol,
|
||||
override val module: FirModuleData,
|
||||
override val compatibility: Map<Incompatible<FirBasedSymbol<*>>, List<KtSymbol>>,
|
||||
override val compatibility: Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<KtSymbol>>,
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.NoActualForExpect(), KtAbstractFirDiagnostic<KtNamedDeclaration>
|
||||
|
||||
internal class ActualWithoutExpectImpl(
|
||||
override val declaration: KtSymbol,
|
||||
override val compatibility: Map<Incompatible<FirBasedSymbol<*>>, List<KtSymbol>>,
|
||||
override val compatibility: Map<ExpectActualCompatibility<FirBasedSymbol<*>>, List<KtSymbol>>,
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.ActualWithoutExpect(), KtAbstractFirDiagnostic<KtNamedDeclaration>
|
||||
|
||||
+6
@@ -556,6 +556,12 @@ public class FirOldFrontendMPPDiagnosticsWithLightTreeTestGenerated extends Abst
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/hmpp/intermediateActualHasAdditionalSupertypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt57320.kt")
|
||||
public void testKt57320() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/hmpp/kt57320.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt-55570.kt")
|
||||
public void testKt_55570() throws Exception {
|
||||
|
||||
+6
@@ -556,6 +556,12 @@ public class FirOldFrontendMPPDiagnosticsWithPsiTestGenerated extends AbstractFi
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/hmpp/intermediateActualHasAdditionalSupertypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt57320.kt")
|
||||
public void testKt57320() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/hmpp/kt57320.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt-55570.kt")
|
||||
public void testKt_55570() throws Exception {
|
||||
|
||||
+3
-2
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import kotlin.properties.PropertyDelegateProvider
|
||||
@@ -1089,12 +1090,12 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val NO_ACTUAL_FOR_EXPECT by error<KtNamedDeclaration>(PositioningStrategy.INCOMPATIBLE_DECLARATION) {
|
||||
parameter<Symbol>("declaration")
|
||||
parameter<FirModuleData>("module")
|
||||
parameter<Map<Incompatible<Symbol>, Collection<Symbol>>>("compatibility")
|
||||
parameter<Map<ExpectActualCompatibility<Symbol>, Collection<Symbol>>>("compatibility")
|
||||
}
|
||||
|
||||
val ACTUAL_WITHOUT_EXPECT by error<KtNamedDeclaration> {
|
||||
parameter<Symbol>("declaration")
|
||||
parameter<Map<Incompatible<Symbol>, Collection<Symbol>>>("compatibility")
|
||||
parameter<Map<ExpectActualCompatibility<Symbol>, Collection<Symbol>>>("compatibility")
|
||||
}
|
||||
|
||||
val AMBIGUOUS_ACTUALS by error<KtNamedDeclaration>(PositioningStrategy.INCOMPATIBLE_DECLARATION) {
|
||||
|
||||
+3
-2
@@ -100,6 +100,7 @@ import org.jetbrains.kotlin.psi.KtWhenEntry
|
||||
import org.jetbrains.kotlin.psi.KtWhenExpression
|
||||
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
|
||||
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
@@ -593,8 +594,8 @@ object FirErrors {
|
||||
val ACTUAL_FUNCTION_WITH_DEFAULT_ARGUMENTS by error0<PsiElement>()
|
||||
val ACTUAL_ANNOTATION_CONFLICTING_DEFAULT_ARGUMENT_VALUE by error1<PsiElement, FirVariableSymbol<*>>()
|
||||
val EXPECTED_FUNCTION_SOURCE_WITH_DEFAULT_ARGUMENTS_NOT_FOUND by error0<PsiElement>()
|
||||
val NO_ACTUAL_FOR_EXPECT by error3<KtNamedDeclaration, FirBasedSymbol<*>, FirModuleData, Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION)
|
||||
val ACTUAL_WITHOUT_EXPECT by error2<KtNamedDeclaration, FirBasedSymbol<*>, Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>()
|
||||
val NO_ACTUAL_FOR_EXPECT by error3<KtNamedDeclaration, FirBasedSymbol<*>, FirModuleData, Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION)
|
||||
val ACTUAL_WITHOUT_EXPECT by error2<KtNamedDeclaration, FirBasedSymbol<*>, Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>()
|
||||
val AMBIGUOUS_ACTUALS by error2<KtNamedDeclaration, FirBasedSymbol<*>, Collection<FirBasedSymbol<*>>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION)
|
||||
val AMBIGUOUS_EXPECTS by error2<KtNamedDeclaration, FirBasedSymbol<*>, Collection<FirModuleData>>(SourceElementPositioningStrategies.INCOMPATIBLE_DECLARATION)
|
||||
val NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS by error2<KtNamedDeclaration, FirBasedSymbol<*>, List<Pair<FirBasedSymbol<*>, Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>>>(SourceElementPositioningStrategies.ACTUAL_DECLARATION_NAME)
|
||||
|
||||
+2
-3
@@ -58,14 +58,13 @@ object FirActualCallableDeclarationChecker : FirCallableDeclarationChecker() {
|
||||
context.session
|
||||
)
|
||||
) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
reporter.reportOn(
|
||||
callableDeclaration.source,
|
||||
FirErrors.ACTUAL_WITHOUT_EXPECT,
|
||||
actualFunctionSymbol,
|
||||
actualFunctionSymbol.expectForActual as Map<ExpectActualCompatibility.Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
actualFunctionSymbol.expectForActual as Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -93,12 +93,11 @@ object FirExpectActualDeclarationChecker : FirBasicDeclarationChecker() {
|
||||
}
|
||||
|
||||
Compatible !in compatibilityToMembersMap -> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.ACTUAL_WITHOUT_EXPECT,
|
||||
symbol,
|
||||
compatibilityToMembersMap as Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
compatibilityToMembersMap,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
+9
-8
@@ -18,13 +18,14 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.ContextIndependentParameterRenderer
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
|
||||
|
||||
class FirPlatformIncompatibilityDiagnosticRenderer(
|
||||
private val mode: MultiplatformDiagnosticRenderingMode
|
||||
) : ContextIndependentParameterRenderer<Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>> {
|
||||
) : ContextIndependentParameterRenderer<Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>> {
|
||||
override fun render(
|
||||
obj: Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
obj: Map<ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
): String {
|
||||
if (obj.isEmpty()) return ""
|
||||
|
||||
@@ -80,33 +81,33 @@ open class MultiplatformDiagnosticRenderingMode {
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderIncompatibilityInformation(
|
||||
map: Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
map: Map<out ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>,
|
||||
indent: String,
|
||||
mode: MultiplatformDiagnosticRenderingMode
|
||||
) {
|
||||
for ((incompatibility, descriptors) in map) {
|
||||
for ((compatibility, descriptors) in map) {
|
||||
append(indent)
|
||||
append("The following declaration")
|
||||
if (descriptors.size == 1) append(" is") else append("s are")
|
||||
append(" incompatible")
|
||||
incompatibility.reason?.let { append(" because $it") }
|
||||
(compatibility as? Incompatible)?.reason?.let { append(" because $it") }
|
||||
append(":")
|
||||
|
||||
mode.renderList(this, descriptors.map { descriptor ->
|
||||
{ mode.renderSymbol(this, descriptor, indent) }
|
||||
})
|
||||
|
||||
if (incompatibility is Incompatible.ClassScopes) {
|
||||
if (compatibility is Incompatible.ClassScopes) {
|
||||
append(indent)
|
||||
append("No actual members are found for expected members listed below:")
|
||||
mode.newLine(this)
|
||||
renderIncompatibleClassScopes(incompatibility.unfulfilled, indent, mode)
|
||||
renderIncompatibleClassScopes(compatibility.unfulfilled, indent, mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderIncompatibleClassScopes(
|
||||
unfulfilled: List<Pair<FirBasedSymbol<*>, Map<Incompatible<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>>,
|
||||
unfulfilled: List<Pair<FirBasedSymbol<*>, Map<out ExpectActualCompatibility<FirBasedSymbol<*>>, Collection<FirBasedSymbol<*>>>>>,
|
||||
indent: String,
|
||||
mode: MultiplatformDiagnosticRenderingMode
|
||||
) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
|
||||
// MODULE: common
|
||||
// TARGET_PLATFORM: Common
|
||||
|
||||
// FILE: StringValue.kt
|
||||
<!NO_ACTUAL_FOR_EXPECT{JS}!>expect class StringValue<!>
|
||||
|
||||
<!NO_ACTUAL_FOR_EXPECT{JS}!>expect fun StringValue.plus(other: String): StringValue<!>
|
||||
|
||||
// MODULE: commonJS()()(common)
|
||||
// TARGET_PLATFORM: JS
|
||||
|
||||
// FILE: StringValue.kt
|
||||
actual class Strin<!NO_ACTUAL_FOR_EXPECT{JS}!>gValue(val value: String<!>)
|
||||
<!NO_ACTUAL_FOR_EXPECT{JS}!>
|
||||
actual fun StringValue.plus(other: String) = StringVal<!>ue(this.value + other)
|
||||
|
||||
// MODULE: intermediate()()(common)
|
||||
// TARGET_PLATFORM: Common
|
||||
|
||||
// FILE: StringDemoInterface.kt
|
||||
expect interface StringDemoInterface
|
||||
|
||||
interface KotlinXStringDemoInterface {
|
||||
val value: String
|
||||
}
|
||||
|
||||
expect fun StringDemoInterface.plusK(): String
|
||||
|
||||
// MODULE: js()()(common, intermediate)
|
||||
// TARGET_PLATFORM: JS
|
||||
|
||||
// FILE: StringDemoInterface.kt
|
||||
actual typealias StringDemoInterface = KotlinXStringDemoInterface
|
||||
|
||||
<!ACTUAL_WITHOUT_EXPECT("actual fun StringDemoInterface.plusK(): <ERROR TYPE REF: Unresolved name: value>; The following declaration is incompatible: expect fun StringDemoInterface.plusK(): String")!>actual fun StringDemoInterface.plusK() = <!RESOLUTION_TO_CLASSIFIER!>StringValue<!>(value).plus("K").<!UNRESOLVED_REFERENCE!>value<!><!>
|
||||
|
||||
// FILE: main.kt
|
||||
class StringDemo(override val value: String) : StringDemoInterface
|
||||
|
||||
fun box() = StringDemo("O").plusK()
|
||||
@@ -0,0 +1,42 @@
|
||||
// !LANGUAGE: +MultiPlatformProjects
|
||||
|
||||
// MODULE: common
|
||||
// TARGET_PLATFORM: Common
|
||||
|
||||
// FILE: StringValue.kt
|
||||
expect class <!NO_ACTUAL_FOR_EXPECT{JS}!>StringValue<!>
|
||||
|
||||
expect fun StringValue.<!NO_ACTUAL_FOR_EXPECT{JS}!>plus<!>(other: String): StringValue
|
||||
|
||||
// MODULE: commonJS()()(common)
|
||||
// TARGET_PLATFORM: JS
|
||||
|
||||
// FILE: StringValue.kt
|
||||
actual class StringValue(val value: String)
|
||||
|
||||
actual fun StringValue.plus(other: String) = StringValue(this.value + other)
|
||||
|
||||
// MODULE: intermediate()()(common)
|
||||
// TARGET_PLATFORM: Common
|
||||
|
||||
// FILE: StringDemoInterface.kt
|
||||
expect interface StringDemoInterface
|
||||
|
||||
interface KotlinXStringDemoInterface {
|
||||
val value: String
|
||||
}
|
||||
|
||||
expect fun StringDemoInterface.plusK(): <!NO_ACTUAL_FOR_EXPECT{JS}!>String<!>
|
||||
|
||||
// MODULE: js()()(common, intermediate)
|
||||
// TARGET_PLATFORM: JS
|
||||
|
||||
// FILE: StringDemoInterface.kt
|
||||
actual typealias StringDemoInterface = KotlinXStringDemoInterface
|
||||
|
||||
actual fun StringDemoInterface.<!ACTUAL_WITHOUT_EXPECT("Actual function 'plusK'; The following declaration is incompatible because return type is different: public expect fun StringDemoInterface /* = KotlinXStringDemoInterface */.plusK(): String")!>plusK<!>() = <!RESOLUTION_TO_CLASSIFIER!>StringValue<!>(value).<!DEBUG_INFO_MISSING_UNRESOLVED!>plus<!>("K").<!DEBUG_INFO_MISSING_UNRESOLVED!>value<!>
|
||||
|
||||
// FILE: main.kt
|
||||
class StringDemo(override val value: String) : StringDemoInterface
|
||||
|
||||
fun box() = StringDemo("O").plusK()
|
||||
Generated
+6
@@ -22257,6 +22257,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/hmpp/intermediateActualHasAdditionalSupertypes.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt57320.kt")
|
||||
public void testKt57320() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/multiplatform/hmpp/kt57320.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kt-55570.kt")
|
||||
public void testKt_55570() throws Exception {
|
||||
|
||||
Reference in New Issue
Block a user