[FIR] Fully expand the bounds of type parameters for canBeNull check
This is required because a not-null bound `Foo` can resolve to a `typealias Foo = Bar?` in which case we must return true. #KT-64645 Fixed
This commit is contained in:
committed by
Space Team
parent
438b2dd164
commit
1018ff280e
@@ -197,7 +197,7 @@ object CheckDispatchReceiver : ResolutionStage() {
|
||||
|
||||
if (smartcastedReceiver != null &&
|
||||
!smartcastedReceiver.isStable &&
|
||||
(isCandidateFromUnstableSmartcast || (isReceiverNullable && !smartcastedReceiver.smartcastType.canBeNull))
|
||||
(isCandidateFromUnstableSmartcast || (isReceiverNullable && !smartcastedReceiver.smartcastType.coneType.canBeNull(callInfo.session)))
|
||||
) {
|
||||
val dispatchReceiverType = (candidate.symbol as? FirCallableSymbol<*>)?.dispatchReceiverType?.let {
|
||||
context.session.typeApproximator.approximateToSuperType(
|
||||
|
||||
+1
-1
@@ -118,7 +118,7 @@ class MemberScopeTowerLevel(
|
||||
// with two exceptions:
|
||||
// - When the smart-casted type is always null, we want to return it and report UNSAFE_CALL.
|
||||
// - When the original type can be null, in this case the smart-case either makes it not-null or the call is red anyway.
|
||||
if (existing == null || dispatchReceiverValue.type.isNullableNothing || receiverTypeWithoutSmartCast.canBeNull) {
|
||||
if (existing == null || dispatchReceiverValue.type.isNullableNothing || receiverTypeWithoutSmartCast.canBeNull(session)) {
|
||||
map[candidateFromSmartCast.member] = MemberFromSmartcastScope(candidateFromSmartCast, DispatchReceiverToUse.SmartcastWithoutUnwrapping)
|
||||
} else {
|
||||
existing.dispatchReceiverToUse = DispatchReceiverToUse.SmartcastIfUnwrappedInvisible
|
||||
|
||||
+6
-5
@@ -368,7 +368,7 @@ abstract class FirDataFlowAnalyzer(
|
||||
if (operandVariable.isReal()) {
|
||||
flow.addImplication((expressionVariable eq isType) implies (operandVariable typeEq type))
|
||||
}
|
||||
if (!type.canBeNull) {
|
||||
if (!type.canBeNull(components.session)) {
|
||||
// x is (T & Any) => x != null
|
||||
flow.addImplication((expressionVariable eq isType) implies (operandVariable notEq null))
|
||||
} else if (type.isMarkedNullable) {
|
||||
@@ -383,7 +383,7 @@ abstract class FirDataFlowAnalyzer(
|
||||
if (operandVariable.isReal()) {
|
||||
flow.addTypeStatement(operandVariable typeEq type)
|
||||
}
|
||||
if (!type.canBeNull) {
|
||||
if (!type.canBeNull(components.session)) {
|
||||
flow.commitOperationStatement(operandVariable notEq null)
|
||||
} else {
|
||||
val expressionVariable = variableStorage.createSynthetic(typeOperatorCall)
|
||||
@@ -998,9 +998,10 @@ abstract class FirDataFlowAnalyzer(
|
||||
for (conditionalEffect in conditionalEffects) {
|
||||
val effect = conditionalEffect.effect as? ConeReturnsEffectDeclaration ?: continue
|
||||
val operation = effect.value.toOperation()
|
||||
val statements = logicSystem.approveContractStatement(conditionalEffect.condition, argumentVariables, substitutor) {
|
||||
logicSystem.approveOperationStatement(flow, it, removeApprovedOrImpossible = operation == null)
|
||||
} ?: continue // TODO: do what if the result is known to be false?
|
||||
val statements =
|
||||
logicSystem.approveContractStatement(conditionalEffect.condition, argumentVariables, substitutor) {
|
||||
logicSystem.approveOperationStatement(flow, it, removeApprovedOrImpossible = operation == null)
|
||||
} ?: continue // TODO: do what if the result is known to be false?
|
||||
if (operation == null) {
|
||||
flow.addAllStatements(statements)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user