FIR IDE: get unstable smartcast from FE1.0-based analysis API
Note that the current FE1.0 implementation still has some limitations 1. only references used as receiver are being considered for smartcast. 2. Somehow the smartcast information is not retained if the for generic typed receivers. See multiSmartcastAsReceiver_stable.descriptors.txt
This commit is contained in:
committed by
Ilya Kirillov
parent
197079c85c
commit
7de0937031
+5
-1
@@ -28,13 +28,17 @@ internal class KtFe10SmartCastProvider(override val analysisSession: KtFe10Analy
|
||||
withValidityAssertion {
|
||||
val bindingContext = analysisSession.analyze(expression)
|
||||
val stableSmartCasts = bindingContext[BindingContext.SMARTCAST, expression]
|
||||
val unstableSmartCasts = bindingContext[BindingContext.UNSTABLE_SMARTCAST, expression]
|
||||
|
||||
return when {
|
||||
stableSmartCasts != null -> {
|
||||
val type = stableSmartCasts.getKtType() ?: return null
|
||||
SmartCastInfo(type, true)
|
||||
}
|
||||
// TODO: collect unstable smartcast here.
|
||||
unstableSmartCasts != null -> {
|
||||
val type = unstableSmartCasts.getKtType() ?: return null
|
||||
SmartCastInfo(type, false)
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: a
|
||||
isStable: null
|
||||
smartCastType: null
|
||||
isStable: false
|
||||
smartCastType: (A & B)
|
||||
|
||||
+2
-2
@@ -1,3 +1,3 @@
|
||||
expression: a
|
||||
isStable: null
|
||||
smartCastType: null
|
||||
isStable: false
|
||||
smartCastType: kotlin.String
|
||||
|
||||
@@ -157,6 +157,7 @@ public interface BindingContext {
|
||||
WritableSlice<KtCollectionLiteralExpression, ResolvedCall<FunctionDescriptor>> COLLECTION_LITERAL_CALL = Slices.createSimpleSlice();
|
||||
|
||||
WritableSlice<KtExpression, ExplicitSmartCasts> SMARTCAST = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtExpression, ExplicitSmartCasts> UNSTABLE_SMARTCAST = new BasicWritableSlice<>(DO_NOTHING);
|
||||
WritableSlice<KtExpression, Boolean> SMARTCAST_NULL = Slices.createSimpleSlice();
|
||||
WritableSlice<KtExpression, ImplicitSmartCasts> IMPLICIT_RECEIVER_SMARTCAST = new BasicWritableSlice<>(DO_NOTHING);
|
||||
|
||||
|
||||
+8
-3
@@ -16,16 +16,19 @@ import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.isNull
|
||||
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.util.*
|
||||
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceExpectedTypeConstraintPosition
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SingleSmartCast
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
|
||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
||||
import org.jetbrains.kotlin.resolve.calls.util.*
|
||||
import org.jetbrains.kotlin.resolve.calls.util.extractCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getCalleeExpressionIfAny
|
||||
import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.util.reportTrailingLambdaErrorOr
|
||||
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstantChecker
|
||||
import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
@@ -358,10 +361,12 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
val argumentExpression = unstableSmartCast.argument.psiExpression ?: return
|
||||
|
||||
require(possibleTypes.isNotEmpty()) { "Receiver for unstable smart cast without possible types" }
|
||||
val intersectWrappedTypes = intersectWrappedTypes(possibleTypes)
|
||||
trace.record(BindingContext.UNSTABLE_SMARTCAST, argumentExpression, SingleSmartCast(null, intersectWrappedTypes))
|
||||
trace.report(
|
||||
SMARTCAST_IMPOSSIBLE.on(
|
||||
argumentExpression,
|
||||
intersectWrappedTypes(possibleTypes),
|
||||
intersectWrappedTypes,
|
||||
argumentExpression.text,
|
||||
dataFlowValue.kind.description
|
||||
)
|
||||
|
||||
+23
-12
@@ -25,8 +25,7 @@ import org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.IMPLICIT_RECEIVER_SMARTCAST
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST
|
||||
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
||||
@@ -37,8 +36,8 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||
import org.jetbrains.kotlin.types.typeUtil.expandIntersectionTypeIfNecessary
|
||||
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
|
||||
class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
||||
|
||||
@@ -232,23 +231,35 @@ class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
||||
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
||||
}
|
||||
|
||||
val oldSmartCasts = trace[SMARTCAST, expression]
|
||||
val newSmartCast = SingleSmartCast(call, type)
|
||||
if (oldSmartCasts != null) {
|
||||
val oldType = oldSmartCasts.type(call)
|
||||
if (oldType != null && oldType != type) {
|
||||
throw AssertionError("Rewriting key $call for smart cast on ${expression.text}")
|
||||
}
|
||||
}
|
||||
trace.record(SMARTCAST, expression, oldSmartCasts?.let { it + newSmartCast } ?: newSmartCast)
|
||||
updateSmartCast(trace, expression, call, type, SMARTCAST)
|
||||
if (recordExpressionType) {
|
||||
//TODO
|
||||
//Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
|
||||
trace.recordType(expression, type)
|
||||
}
|
||||
} else {
|
||||
updateSmartCast(trace, expression, call, type, UNSTABLE_SMARTCAST)
|
||||
trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.text, dataFlowValue.kind.description))
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateSmartCast(
|
||||
trace: BindingTrace,
|
||||
expression: KtExpression,
|
||||
call: Call?,
|
||||
type: KotlinType,
|
||||
key: WritableSlice<KtExpression, ExplicitSmartCasts>?
|
||||
) {
|
||||
val oldSmartCasts = trace[key, expression]
|
||||
val newSmartCast = SingleSmartCast(call, type)
|
||||
if (oldSmartCasts != null) {
|
||||
val oldType = oldSmartCasts.type(call)
|
||||
if (oldType != null && oldType != type) {
|
||||
throw AssertionError("Rewriting key $call for smart cast on ${expression.text}")
|
||||
}
|
||||
}
|
||||
val updatedSmartCasts = oldSmartCasts?.let { it + newSmartCast } ?: newSmartCast
|
||||
trace.record(key, expression, updatedSmartCasts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user