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
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker
|
||||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper
|
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper
|
||||||
import org.jetbrains.kotlin.container.*
|
import org.jetbrains.kotlin.container.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.checkers.*
|
import org.jetbrains.kotlin.resolve.calls.checkers.*
|
||||||
@@ -128,6 +129,7 @@ abstract class PlatformConfiguratorBase(
|
|||||||
private val identifierChecker: IdentifierChecker? = null,
|
private val identifierChecker: IdentifierChecker? = null,
|
||||||
private val overloadFilter: OverloadFilter? = null,
|
private val overloadFilter: OverloadFilter? = null,
|
||||||
private val platformToKotlinClassMapper: PlatformToKotlinClassMapper? = null,
|
private val platformToKotlinClassMapper: PlatformToKotlinClassMapper? = null,
|
||||||
|
private val platformSpecificCastChecker: PlatformSpecificCastChecker? = null,
|
||||||
private val delegationFilter: DelegationFilter? = null,
|
private val delegationFilter: DelegationFilter? = null,
|
||||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper? = null,
|
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper? = null,
|
||||||
private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer? = null
|
private val declarationReturnTypeSanitizer: DeclarationReturnTypeSanitizer? = null
|
||||||
@@ -154,6 +156,7 @@ abstract class PlatformConfiguratorBase(
|
|||||||
useInstanceIfNotNull(identifierChecker)
|
useInstanceIfNotNull(identifierChecker)
|
||||||
useInstanceIfNotNull(overloadFilter)
|
useInstanceIfNotNull(overloadFilter)
|
||||||
useInstanceIfNotNull(platformToKotlinClassMapper)
|
useInstanceIfNotNull(platformToKotlinClassMapper)
|
||||||
|
useInstanceIfNotNull(platformSpecificCastChecker)
|
||||||
useInstanceIfNotNull(delegationFilter)
|
useInstanceIfNotNull(delegationFilter)
|
||||||
useInstanceIfNotNull(overridesBackwardCompatibilityHelper)
|
useInstanceIfNotNull(overridesBackwardCompatibilityHelper)
|
||||||
useInstanceIfNotNull(declarationReturnTypeSanitizer)
|
useInstanceIfNotNull(declarationReturnTypeSanitizer)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.types
|
|||||||
import com.google.common.collect.Maps
|
import com.google.common.collect.Maps
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker
|
||||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper
|
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper
|
||||||
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
|
||||||
import org.jetbrains.kotlin.builtins.isFunctionType
|
import org.jetbrains.kotlin.builtins.isFunctionType
|
||||||
@@ -41,11 +42,12 @@ object CastDiagnosticsUtil {
|
|||||||
fun isCastPossible(
|
fun isCastPossible(
|
||||||
lhsType: KotlinType,
|
lhsType: KotlinType,
|
||||||
rhsType: KotlinType,
|
rhsType: KotlinType,
|
||||||
platformToKotlinClassMapper: PlatformToKotlinClassMapper
|
platformToKotlinClassMapper: PlatformToKotlinClassMapper,
|
||||||
|
platformSpecificCastChecker: PlatformSpecificCastChecker
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val typeConstructor = lhsType.constructor
|
val typeConstructor = lhsType.constructor
|
||||||
if (typeConstructor is IntersectionTypeConstructor) {
|
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 rhsNullable = TypeUtils.isNullableType(rhsType)
|
||||||
val lhsNullable = TypeUtils.isNullableType(lhsType)
|
val lhsNullable = TypeUtils.isNullableType(lhsType)
|
||||||
@@ -59,6 +61,7 @@ object CastDiagnosticsUtil {
|
|||||||
// This is an oversimplification (which does not render the method incomplete):
|
// 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
|
// 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 (TypeUtils.isTypeParameter(lhsType) || TypeUtils.isTypeParameter(rhsType)) return true
|
||||||
|
if (platformSpecificCastChecker.isCastPossible(lhsType, rhsType)) return true
|
||||||
|
|
||||||
if (isFinal(lhsType) || isFinal(rhsType)) return false
|
if (isFinal(lhsType) || isFinal(rhsType)) return false
|
||||||
if (isTrait(lhsType) || isTrait(rhsType)) return true
|
if (isTrait(lhsType) || isTrait(rhsType)) return true
|
||||||
|
|||||||
+1
-1
@@ -376,7 +376,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return;
|
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()));
|
context.trace.report(CAST_NEVER_SUCCEEDS.on(expression.getOperationReference()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+7
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.types.expressions;
|
|||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||||
|
import org.jetbrains.kotlin.builtins.PlatformSpecificCastChecker;
|
||||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper;
|
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMapper;
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
import org.jetbrains.kotlin.config.LanguageVersionSettings;
|
||||||
import org.jetbrains.kotlin.context.GlobalContext;
|
import org.jetbrains.kotlin.context.GlobalContext;
|
||||||
@@ -36,6 +37,7 @@ public class ExpressionTypingComponents {
|
|||||||
public ExpressionTypingServices expressionTypingServices;
|
public ExpressionTypingServices expressionTypingServices;
|
||||||
public CallResolver callResolver;
|
public CallResolver callResolver;
|
||||||
public PlatformToKotlinClassMapper platformToKotlinClassMapper;
|
public PlatformToKotlinClassMapper platformToKotlinClassMapper;
|
||||||
|
public PlatformSpecificCastChecker platformSpecificCastChecker;
|
||||||
public ControlStructureTypingUtils controlStructureTypingUtils;
|
public ControlStructureTypingUtils controlStructureTypingUtils;
|
||||||
public ForLoopConventionsChecker forLoopConventionsChecker;
|
public ForLoopConventionsChecker forLoopConventionsChecker;
|
||||||
public FakeCallResolver fakeCallResolver;
|
public FakeCallResolver fakeCallResolver;
|
||||||
@@ -100,6 +102,11 @@ public class ExpressionTypingComponents {
|
|||||||
this.platformToKotlinClassMapper = platformToKotlinClassMapper;
|
this.platformToKotlinClassMapper = platformToKotlinClassMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public void setPlatformToKotlinClassMap(@NotNull PlatformSpecificCastChecker platformSpecificCastChecker) {
|
||||||
|
this.platformSpecificCastChecker = platformSpecificCastChecker;
|
||||||
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void setControlStructureTypingUtils(@NotNull ControlStructureTypingUtils controlStructureTypingUtils) {
|
public void setControlStructureTypingUtils(@NotNull ControlStructureTypingUtils controlStructureTypingUtils) {
|
||||||
this.controlStructureTypingUtils = controlStructureTypingUtils;
|
this.controlStructureTypingUtils = controlStructureTypingUtils;
|
||||||
|
|||||||
+1
-1
@@ -678,7 +678,7 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping
|
|||||||
.takeIf { it.isNotEmpty() }
|
.takeIf { it.isNotEmpty() }
|
||||||
?: possibleTypes
|
?: 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))
|
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<!>
|
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 testCheckedAs1(x : lib.FwdStruct) = x as cnames.structs.FwdStruct
|
||||||
fun testCheckedAs2(x : lib.FwdObjcClass) = x <!CAST_NEVER_SUCCEEDS!>as<!> objcnames.classes.FwdObjcClass
|
fun testCheckedAs2(x : lib.FwdObjcClass) = x as objcnames.classes.FwdObjcClass
|
||||||
fun testCheckedAs3(x : lib.FwdProtocol) = x as objcnames.protocols.FwdProtocol
|
fun testCheckedAs3(x : lib.FwdProtocol) = x as objcnames.protocols.FwdProtocol
|
||||||
fun testCheckedSafeAs4(x : lib.FwdStruct) = x <!CAST_NEVER_SUCCEEDS!>as?<!> cnames.structs.FwdStruct
|
fun testCheckedSafeAs4(x : lib.FwdStruct) = x as? cnames.structs.FwdStruct
|
||||||
fun testCheckedSafeAs5(x : lib.FwdObjcClass) = x <!CAST_NEVER_SUCCEEDS!>as?<!> objcnames.classes.FwdObjcClass
|
fun testCheckedSafeAs5(x : lib.FwdObjcClass) = x as? objcnames.classes.FwdObjcClass
|
||||||
fun testCheckedSafeAs6(x : lib.FwdProtocol) = x as? objcnames.protocols.FwdProtocol
|
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 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 <!CAST_NEVER_SUCCEEDS!>as<!> objcnames.classes.FwdObjcClass<!>
|
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 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,
|
NativeObjCNameChecker, NativeObjCNameOverridesChecker,
|
||||||
NativeObjCRefinementChecker, NativeObjCRefinementAnnotationChecker,
|
NativeObjCRefinementChecker, NativeObjCRefinementAnnotationChecker,
|
||||||
NativeObjCRefinementOverridesChecker, NativeHiddenFromObjCInheritanceChecker,
|
NativeObjCRefinementOverridesChecker, NativeHiddenFromObjCInheritanceChecker,
|
||||||
)
|
),
|
||||||
|
platformSpecificCastChecker = NativePlatformSpecificCastChecker
|
||||||
) {
|
) {
|
||||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||||
container.useInstance(NativeInliningRule)
|
container.useInstance(NativeInliningRule)
|
||||||
|
|||||||
Reference in New Issue
Block a user