Don't emit CAST_NEVER_SUCCEEDS when casting to a forward declaration type
^KT-58929
This commit is contained in:
committed by
Space Team
parent
28f90b3ea8
commit
53584cdd49
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker
|
||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper
|
||||
import org.jetbrains.kotlin.container.*
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.*
|
||||
@@ -128,6 +129,7 @@ abstract class PlatformConfiguratorBase(
|
||||
private val identifierChecker: IdentifierChecker? = null,
|
||||
private val overloadFilter: OverloadFilter? = null,
|
||||
private val platformToKotlinClassMapper: PlatformToKotlinClassMapper? = null,
|
||||
private val platformSpecificCastChecker: PlatformSpecificCastChecker? = null,
|
||||
private val delegationFilter: DelegationFilter? = null,
|
||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper? = null,
|
||||
private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer? = null
|
||||
@@ -154,6 +156,7 @@ abstract class PlatformConfiguratorBase(
|
||||
useInstanceIfNotNull(identifierChecker)
|
||||
useInstanceIfNotNull(overloadFilter)
|
||||
useInstanceIfNotNull(platformToKotlinClassMapper)
|
||||
useInstanceIfNotNull(platformSpecificCastChecker)
|
||||
useInstanceIfNotNull(delegationFilter)
|
||||
useInstanceIfNotNull(overridesBackwardCompatibilityHelper)
|
||||
useInstanceIfNotNull(declarationReturnTypeSanitizer)
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.types
|
||||
import com.google.common.collect.Maps
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker
|
||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper
|
||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||
@@ -41,11 +42,12 @@ object CastDiagnosticsUtil {
|
||||
fun isCastPossible(
|
||||
lhsType: KotlinType,
|
||||
rhsType: KotlinType,
|
||||
platformToKotlinClassMapper: PlatformToKotlinClassMapper
|
||||
platformToKotlinClassMapper: PlatformToKotlinClassMapper,
|
||||
platformSpecificCastChecker: PlatformSpecificCastChecker
|
||||
): Boolean {
|
||||
val typeConstructor = lhsType.constructor
|
||||
if (typeConstructor is IntersectionTypeConstructor) {
|
||||
return typeConstructor.supertypes.any { isCastPossible(it, rhsType, platformToKotlinClassMapper) }
|
||||
return typeConstructor.supertypes.any { isCastPossible(it, rhsType, platformToKotlinClassMapper, platformSpecificCastChecker) }
|
||||
}
|
||||
val rhsNullable = TypeUtils.isNullableType(rhsType)
|
||||
val lhsNullable = TypeUtils.isNullableType(lhsType)
|
||||
@@ -59,6 +61,7 @@ object CastDiagnosticsUtil {
|
||||
// This is an oversimplification (which does not render the method incomplete):
|
||||
// we consider any type parameter capable of taking any value, which may be made more precise if we considered bounds
|
||||
if (TypeUtils.isTypeParameter(lhsType) || TypeUtils.isTypeParameter(rhsType)) return true
|
||||
if (platformSpecificCastChecker.isCastPossible(lhsType, rhsType)) return true
|
||||
|
||||
if (isFinal(lhsType) || isFinal(rhsType)) return false
|
||||
if (isTrait(lhsType) || isTrait(rhsType)) return true
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!TypeUtilsKt.isStubType(actualType) && !CastDiagnosticsUtil.isCastPossible(actualType, targetType, components.platformToKotlinClassMapper)) {
|
||||
if (!TypeUtilsKt.isStubType(actualType) && !CastDiagnosticsUtil.isCastPossible(actualType, targetType, components.platformToKotlinClassMapper, components.platformSpecificCastChecker)) {
|
||||
context.trace.report(CAST_NEVER_SUCCEEDS.on(expression.getOperationReference()));
|
||||
return;
|
||||
}
|
||||
|
||||
+7
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.types.expressions;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker;
|
||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||
import org.jetbrains.kotlin.context.GlobalContext;
|
||||
@@ -36,6 +37,7 @@ public class ExpressionTypingComponents {
|
||||
public ExpressionTypingServices expressionTypingServices;
|
||||
public CallResolver callResolver;
|
||||
public PlatformToKotlinClassMapper platformToKotlinClassMapper;
|
||||
public PlatformSpecificCastChecker platformSpecificCastChecker;
|
||||
public ControlStructureTypingUtils controlStructureTypingUtils;
|
||||
public ForLoopConventionsChecker forLoopConventionsChecker;
|
||||
public FakeCallResolver fakeCallResolver;
|
||||
@@ -100,6 +102,11 @@ public class ExpressionTypingComponents {
|
||||
this.platformToKotlinClassMapper = platformToKotlinClassMapper;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setPlatformToKotlinClassMap(@NotNull PlatformSpecificCastChecker platformSpecificCastChecker) {
|
||||
this.platformSpecificCastChecker = platformSpecificCastChecker;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public void setControlStructureTypingUtils(@NotNull ControlStructureTypingUtils controlStructureTypingUtils) {
|
||||
this.controlStructureTypingUtils = controlStructureTypingUtils;
|
||||
|
||||
+1
-1
@@ -678,7 +678,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
||||
.takeIf { it.isNotEmpty() }
|
||||
?: possibleTypes
|
||||
|
||||
if (nonTrivialTypes.none { CastDiagnosticsUtil.isCastPossible(it, targetType, components.platformToKotlinClassMapper) }) {
|
||||
if (nonTrivialTypes.none { CastDiagnosticsUtil.isCastPossible(it, targetType, components.platformToKotlinClassMapper, components.platformSpecificCastChecker) }) {
|
||||
context.trace.report(USELESS_IS_CHECK.on(isCheck, negated))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,15 +92,15 @@ fun testInline4() {
|
||||
val c : (objcnames.protocols.FwdProtocol) -> Unit = ::<!FORWARD_DECLARATION_AS_REIFIED_TYPE_ARGUMENT!>inlineF<!>
|
||||
}
|
||||
|
||||
fun testCheckedAs1(x : lib.FwdStruct) = x <!CAST_NEVER_SUCCEEDS!>as<!> cnames.structs.FwdStruct
|
||||
fun testCheckedAs2(x : lib.FwdObjcClass) = x <!CAST_NEVER_SUCCEEDS!>as<!> objcnames.classes.FwdObjcClass
|
||||
fun testCheckedAs1(x : lib.FwdStruct) = x as cnames.structs.FwdStruct
|
||||
fun testCheckedAs2(x : lib.FwdObjcClass) = x as objcnames.classes.FwdObjcClass
|
||||
fun testCheckedAs3(x : lib.FwdProtocol) = x as objcnames.protocols.FwdProtocol
|
||||
fun testCheckedSafeAs4(x : lib.FwdStruct) = x <!CAST_NEVER_SUCCEEDS!>as?<!> cnames.structs.FwdStruct
|
||||
fun testCheckedSafeAs5(x : lib.FwdObjcClass) = x <!CAST_NEVER_SUCCEEDS!>as?<!> objcnames.classes.FwdObjcClass
|
||||
fun testCheckedSafeAs4(x : lib.FwdStruct) = x as? cnames.structs.FwdStruct
|
||||
fun testCheckedSafeAs5(x : lib.FwdObjcClass) = x as? objcnames.classes.FwdObjcClass
|
||||
fun testCheckedSafeAs6(x : lib.FwdProtocol) = x as? objcnames.protocols.FwdProtocol
|
||||
|
||||
fun testUnCheckedAs1(x : lib2.FwdStruct) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x <!CAST_NEVER_SUCCEEDS!>as<!> cnames.structs.FwdStruct<!>
|
||||
fun testUnCheckedAs2(x : lib2.FwdObjcClass) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x <!CAST_NEVER_SUCCEEDS!>as<!> objcnames.classes.FwdObjcClass<!>
|
||||
fun testUnCheckedAs1(x : lib2.FwdStruct) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x as cnames.structs.FwdStruct<!>
|
||||
fun testUnCheckedAs2(x : lib2.FwdObjcClass) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x as objcnames.classes.FwdObjcClass<!>
|
||||
fun testUnCheckedAs3(x : lib2.FwdProtocol) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x as objcnames.protocols.FwdProtocol<!>
|
||||
|
||||
fun testUnCheckedAs4(x : lib.FwdStruct) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x <!CAST_NEVER_SUCCEEDS!>as<!> objcnames.classes.FwdObjcClass<!>
|
||||
fun testUnCheckedAs4(x : lib.FwdStruct) = <!UNCHECKED_CAST_TO_FORWARD_DECLARATION!>x as objcnames.classes.FwdObjcClass<!>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
package org.jetbrains.kotlin.builtins
|
||||
|
||||
import org.jetbrains.kotlin.container.DefaultImplementation
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
@DefaultImplementation(impl = PlatformSpecificCastChecker.Default::class)
|
||||
interface PlatformSpecificCastChecker {
|
||||
fun isCastPossible(fromType: KotlinType, toType: KotlinType): Boolean
|
||||
|
||||
class Default : PlatformSpecificCastChecker {
|
||||
override fun isCastPossible(fromType: KotlinType, toType: KotlinType): Boolean {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.resolve.konan.diagnostics
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.konan.getForwardDeclarationKindOrNull
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
object NativePlatformSpecificCastChecker : PlatformSpecificCastChecker {
|
||||
override fun isCastPossible(fromType: KotlinType, toType: KotlinType): Boolean {
|
||||
return isCastToAForwardDeclaration(toType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Here, we only check that we are casting to a forward declaration to suppress a CAST_NEVER_SUCCEEDS warning. The cast is further
|
||||
* checked in NativeForwardDeclarationRttiChecker.
|
||||
*/
|
||||
private fun isCastToAForwardDeclaration(forwardDeclarationType: KotlinType): Boolean {
|
||||
val forwardDeclarationClassDescriptor = forwardDeclarationType.constructor.declarationDescriptor
|
||||
if (forwardDeclarationClassDescriptor !is ClassDescriptor) return false
|
||||
return forwardDeclarationClassDescriptor.getForwardDeclarationKindOrNull() != null
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -30,7 +30,8 @@ object NativePlatformConfigurator : PlatformConfiguratorBase(
|
||||
NativeObjCNameChecker, NativeObjCNameOverridesChecker,
|
||||
NativeObjCRefinementChecker, NativeObjCRefinementAnnotationChecker,
|
||||
NativeObjCRefinementOverridesChecker, NativeHiddenFromObjCInheritanceChecker,
|
||||
)
|
||||
),
|
||||
platformSpecificCastChecker = NativePlatformSpecificCastChecker
|
||||
) {
|
||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||
container.useInstance(NativeInliningRule)
|
||||
|
||||
Reference in New Issue
Block a user