Fix unsound smartcast due to returns(null) in safecall
^KT-26382 Fixed
This commit is contained in:
@@ -19,12 +19,11 @@ package org.jetbrains.kotlin.contracts
|
|||||||
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
import org.jetbrains.kotlin.builtins.DefaultBuiltIns
|
||||||
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
|
import org.jetbrains.kotlin.contracts.interpretation.ContractInterpretationDispatcher
|
||||||
import org.jetbrains.kotlin.contracts.model.Computation
|
import org.jetbrains.kotlin.contracts.model.Computation
|
||||||
|
import org.jetbrains.kotlin.contracts.model.ConditionalEffect
|
||||||
|
import org.jetbrains.kotlin.contracts.model.ESEffect
|
||||||
import org.jetbrains.kotlin.contracts.model.Functor
|
import org.jetbrains.kotlin.contracts.model.Functor
|
||||||
import org.jetbrains.kotlin.contracts.model.functors.*
|
import org.jetbrains.kotlin.contracts.model.functors.*
|
||||||
import org.jetbrains.kotlin.contracts.model.structure.CallComputation
|
import org.jetbrains.kotlin.contracts.model.structure.*
|
||||||
import org.jetbrains.kotlin.contracts.model.structure.ESConstant
|
|
||||||
import org.jetbrains.kotlin.contracts.model.structure.UNKNOWN_COMPUTATION
|
|
||||||
import org.jetbrains.kotlin.contracts.model.structure.lift
|
|
||||||
import org.jetbrains.kotlin.contracts.parsing.isEqualsDescriptor
|
import org.jetbrains.kotlin.contracts.parsing.isEqualsDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
@@ -114,6 +113,20 @@ class EffectsExtractingVisitor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitSafeQualifiedExpression(expression: KtSafeQualifiedExpression, data: Unit?): Computation {
|
||||||
|
val computation = super.visitSafeQualifiedExpression(expression, data)
|
||||||
|
if (computation === UNKNOWN_COMPUTATION) return computation
|
||||||
|
|
||||||
|
// For safecall any clauses of form 'returns(null) -> ...' are incorrect, because safecall can return
|
||||||
|
// null bypassing function's contract, so we have to filter them out
|
||||||
|
|
||||||
|
fun ESEffect.containsReturnsNull(): Boolean =
|
||||||
|
this == ESReturns(ESConstant.NULL) || this is ConditionalEffect && this.simpleEffect.containsReturnsNull()
|
||||||
|
|
||||||
|
val effectsWithoutReturnsNull = computation.effects.filter { !it.containsReturnsNull() }
|
||||||
|
return CallComputation(computation.type, effectsWithoutReturnsNull)
|
||||||
|
}
|
||||||
|
|
||||||
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): Computation {
|
override fun visitBinaryExpression(expression: KtBinaryExpression, data: Unit): Computation {
|
||||||
val left = extractOrGetCached(expression.left ?: return UNKNOWN_COMPUTATION)
|
val left = extractOrGetCached(expression.left ?: return UNKNOWN_COMPUTATION)
|
||||||
val right = extractOrGetCached(expression.right ?: return UNKNOWN_COMPUTATION)
|
val right = extractOrGetCached(expression.right ?: return UNKNOWN_COMPUTATION)
|
||||||
|
|||||||
Vendored
+1
-1
@@ -12,6 +12,6 @@ fun Any.nullWhenString(): Any? {
|
|||||||
|
|
||||||
fun test(x: Int?) {
|
fun test(x: Int?) {
|
||||||
if (x?.nullWhenString() == null) {
|
if (x?.nullWhenString() == null) {
|
||||||
<!DEBUG_INFO_SMARTCAST!>x<!>.length
|
x.<!UNRESOLVED_REFERENCE!>length<!>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user