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 {
|
withValidityAssertion {
|
||||||
val bindingContext = analysisSession.analyze(expression)
|
val bindingContext = analysisSession.analyze(expression)
|
||||||
val stableSmartCasts = bindingContext[BindingContext.SMARTCAST, expression]
|
val stableSmartCasts = bindingContext[BindingContext.SMARTCAST, expression]
|
||||||
|
val unstableSmartCasts = bindingContext[BindingContext.UNSTABLE_SMARTCAST, expression]
|
||||||
|
|
||||||
return when {
|
return when {
|
||||||
stableSmartCasts != null -> {
|
stableSmartCasts != null -> {
|
||||||
val type = stableSmartCasts.getKtType() ?: return null
|
val type = stableSmartCasts.getKtType() ?: return null
|
||||||
SmartCastInfo(type, true)
|
SmartCastInfo(type, true)
|
||||||
}
|
}
|
||||||
// TODO: collect unstable smartcast here.
|
unstableSmartCasts != null -> {
|
||||||
|
val type = unstableSmartCasts.getKtType() ?: return null
|
||||||
|
SmartCastInfo(type, false)
|
||||||
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
expression: a
|
expression: a
|
||||||
isStable: null
|
isStable: false
|
||||||
smartCastType: null
|
smartCastType: (A & B)
|
||||||
|
|||||||
+2
-2
@@ -1,3 +1,3 @@
|
|||||||
expression: a
|
expression: a
|
||||||
isStable: null
|
isStable: false
|
||||||
smartCastType: null
|
smartCastType: kotlin.String
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ public interface BindingContext {
|
|||||||
WritableSlice<KtCollectionLiteralExpression, ResolvedCall<FunctionDescriptor>> COLLECTION_LITERAL_CALL = Slices.createSimpleSlice();
|
WritableSlice<KtCollectionLiteralExpression, ResolvedCall<FunctionDescriptor>> COLLECTION_LITERAL_CALL = Slices.createSimpleSlice();
|
||||||
|
|
||||||
WritableSlice<KtExpression, ExplicitSmartCasts> SMARTCAST = new BasicWritableSlice<>(DO_NOTHING);
|
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, Boolean> SMARTCAST_NULL = Slices.createSimpleSlice();
|
||||||
WritableSlice<KtExpression, ImplicitSmartCasts> IMPLICIT_RECEIVER_SMARTCAST = new BasicWritableSlice<>(DO_NOTHING);
|
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.isNull
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
|
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
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.context.BasicCallResolutionContext
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceExpectedTypeConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceExpectedTypeConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
import org.jetbrains.kotlin.resolve.calls.inference.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
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.smartcasts.SmartCastManager
|
||||||
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
|
||||||
import org.jetbrains.kotlin.resolve.calls.tower.*
|
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.CompileTimeConstantChecker
|
||||||
import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
|
import org.jetbrains.kotlin.resolve.constants.TypedCompileTimeConstant
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||||
@@ -358,10 +361,12 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
val argumentExpression = unstableSmartCast.argument.psiExpression ?: return
|
val argumentExpression = unstableSmartCast.argument.psiExpression ?: return
|
||||||
|
|
||||||
require(possibleTypes.isNotEmpty()) { "Receiver for unstable smart cast without possible types" }
|
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(
|
trace.report(
|
||||||
SMARTCAST_IMPOSSIBLE.on(
|
SMARTCAST_IMPOSSIBLE.on(
|
||||||
argumentExpression,
|
argumentExpression,
|
||||||
intersectWrappedTypes(possibleTypes),
|
intersectWrappedTypes,
|
||||||
argumentExpression.text,
|
argumentExpression.text,
|
||||||
dataFlowValue.kind.description
|
dataFlowValue.kind.description
|
||||||
)
|
)
|
||||||
|
|||||||
+24
-13
@@ -25,8 +25,7 @@ import org.jetbrains.kotlin.diagnostics.Errors.SMARTCAST_IMPOSSIBLE
|
|||||||
import org.jetbrains.kotlin.psi.Call
|
import org.jetbrains.kotlin.psi.Call
|
||||||
import org.jetbrains.kotlin.psi.KtExpression
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.IMPLICIT_RECEIVER_SMARTCAST
|
import org.jetbrains.kotlin.resolve.BindingContext.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext.SMARTCAST
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||||
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
|
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.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
import org.jetbrains.kotlin.types.checker.intersectWrappedTypes
|
||||||
import org.jetbrains.kotlin.types.typeUtil.expandIntersectionTypeIfNecessary
|
import org.jetbrains.kotlin.types.typeUtil.expandIntersectionTypeIfNecessary
|
||||||
|
import org.jetbrains.kotlin.util.slicedMap.WritableSlice
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
||||||
|
|
||||||
@@ -232,7 +231,26 @@ class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
|||||||
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
trace.report(Errors.DEPRECATED_SMARTCAST.on(expression, type, expression.text, dataFlowValue.kind.description))
|
||||||
}
|
}
|
||||||
|
|
||||||
val oldSmartCasts = trace[SMARTCAST, expression]
|
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)
|
val newSmartCast = SingleSmartCast(call, type)
|
||||||
if (oldSmartCasts != null) {
|
if (oldSmartCasts != null) {
|
||||||
val oldType = oldSmartCasts.type(call)
|
val oldType = oldSmartCasts.type(call)
|
||||||
@@ -240,15 +258,8 @@ class SmartCastManager(private val argumentTypeResolver: ArgumentTypeResolver) {
|
|||||||
throw AssertionError("Rewriting key $call for smart cast on ${expression.text}")
|
throw AssertionError("Rewriting key $call for smart cast on ${expression.text}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trace.record(SMARTCAST, expression, oldSmartCasts?.let { it + newSmartCast } ?: newSmartCast)
|
val updatedSmartCasts = oldSmartCasts?.let { it + newSmartCast } ?: newSmartCast
|
||||||
if (recordExpressionType) {
|
trace.record(key, expression, updatedSmartCasts)
|
||||||
//TODO
|
|
||||||
//Why the expression type is rewritten for receivers and is not rewritten for arguments? Is it necessary?
|
|
||||||
trace.recordType(expression, type)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.text, dataFlowValue.kind.description))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user