[Misc] Get rid of public Companion methods in SmartCastManager

It's necessary for type-refinement component to be injected
This commit is contained in:
Denis Zharkov
2019-04-24 12:16:45 +03:00
committed by Dmitry Savvinov
parent e7d6a9508e
commit 529763b9bd
6 changed files with 105 additions and 110 deletions
@@ -377,7 +377,7 @@ class CandidateResolver(
val spreadElement = argument.getSpreadElement() val spreadElement = argument.getSpreadElement()
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) { if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, type, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, type, context)
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast( val smartCastResult = smartCastManager.checkAndRecordPossibleCast(
dataFlowValue, expectedType, expression, context, dataFlowValue, expectedType, expression, context,
call = null, recordExpressionType = false call = null, recordExpressionType = false
) )
@@ -544,11 +544,10 @@ class CandidateResolver(
} else if (!nullableImplicitInvokeReceiver && smartCastNeeded) { } else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
// Look if smart cast has some useful nullability info // Look if smart cast has some useful nullability info
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast( val smartCastResult = smartCastManager.checkAndRecordPossibleCast(
dataFlowValue, expectedReceiverParameterType, dataFlowValue, expectedReceiverParameterType,
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
expression, this, candidateCall.call, recordExpressionType = true expression, this, candidateCall.call, recordExpressionType = true
) ) { possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) }
if (smartCastResult == null) { if (smartCastResult == null) {
if (notNullReceiverExpected) { if (notNullReceiverExpected) {
@@ -39,7 +39,8 @@ class DiagnosticReporterByTrackingStrategy(
val context: BasicCallResolutionContext, val context: BasicCallResolutionContext,
val psiKotlinCall: PSIKotlinCall, val psiKotlinCall: PSIKotlinCall,
val dataFlowValueFactory: DataFlowValueFactory, val dataFlowValueFactory: DataFlowValueFactory,
val allDiagnostics: List<KotlinCallDiagnostic> val allDiagnostics: List<KotlinCallDiagnostic>,
private val smartCastManager: SmartCastManager
) : DiagnosticReporter { ) : DiagnosticReporter {
private val trace = context.trace as TrackingBindingTrace private val trace = context.trace as TrackingBindingTrace
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
@@ -195,7 +196,7 @@ class DiagnosticReporterByTrackingStrategy(
) )
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
val call = if (call.callElement is KtBinaryExpression) null else call val call = if (call.callElement is KtBinaryExpression) null else call
SmartCastManager.checkAndRecordPossibleCast( smartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call, dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
recordExpressionType = true recordExpressionType = true
) )
@@ -204,7 +205,7 @@ class DiagnosticReporterByTrackingStrategy(
trace.markAsReported() trace.markAsReported()
val receiverValue = expressionArgument.receiver.receiverValue val receiverValue = expressionArgument.receiver.receiverValue
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, context) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, context)
SmartCastManager.checkAndRecordPossibleCast( smartCastManager.checkAndRecordPossibleCast(
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call, dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
recordExpressionType = true recordExpressionType = true
) )
@@ -340,6 +341,5 @@ class DiagnosticReporterByTrackingStrategy(
} }
val NewConstraintError.upperKotlinType get() = upperType as KotlinType val NewConstraintError.upperKotlinType get() = upperType as KotlinType
val NewConstraintError.lowerKotlinType get() = lowerType as KotlinType val NewConstraintError.lowerKotlinType get() = lowerType as KotlinType
@@ -119,13 +119,89 @@ class SmartCastManager {
else -> null else -> null
} }
fun checkAndRecordPossibleCast(
dataFlowValue: DataFlowValue,
expectedType: KotlinType,
expression: KtExpression?,
c: ResolutionContext<*>,
call: Call?,
recordExpressionType: Boolean,
additionalPredicate: ((KotlinType) -> Boolean)? = null
): SmartCastResult? {
val calleeExpression = call?.calleeExpression
val expectedTypes = if (c.languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
expectedType.expandIntersectionTypeIfNecessary()
else
listOf(expectedType)
for (possibleType in c.dataFlowInfo.getCollectedTypes(dataFlowValue, c.languageVersionSettings)) {
if (expectedTypes.any { ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, it) } &&
(additionalPredicate == null || additionalPredicate(possibleType))
) {
if (expression != null) {
recordCastOrError(expression, possibleType, c.trace, dataFlowValue, call, recordExpressionType)
} else if (calleeExpression != null && dataFlowValue.isStable) {
val receiver = (dataFlowValue.identifierInfo as? IdentifierInfo.Receiver)?.value
if (receiver is ImplicitReceiver) {
val oldSmartCasts = c.trace[IMPLICIT_RECEIVER_SMARTCAST, calleeExpression]
val newSmartCasts = ImplicitSmartCasts(receiver, possibleType)
if (oldSmartCasts != null) {
val oldType = oldSmartCasts.receiverTypes[receiver]
if (oldType != null && oldType != possibleType) {
throw AssertionError(
"Rewriting key $receiver for implicit smart cast on ${calleeExpression.text}: " +
"was $oldType, now $possibleType"
)
}
}
c.trace.record(IMPLICIT_RECEIVER_SMARTCAST, calleeExpression,
oldSmartCasts?.let { it + newSmartCasts } ?: newSmartCasts)
}
}
return SmartCastResult(possibleType, dataFlowValue.isStable)
}
}
if (!c.dataFlowInfo.getCollectedNullability(dataFlowValue).canBeNull() && !expectedType.isMarkedNullable) {
// Handling cases like:
// fun bar(x: Any) {}
// fun <T : Any?> foo(x: T) {
// if (x != null) {
// bar(x) // Should be allowed with smart cast
// }
// }
//
// It doesn't handled by lower code with getPossibleTypes because smart cast of T after `x != null` is still has same type T.
// But at the same time we're sure that `x` can't be null and just check for such cases manually
// E.g. in case x!! when x has type of T where T is type parameter with nullable upper bounds
// x!! is immanently not null (see DataFlowValueFactory.createDataFlowValue for expression)
val immanentlyNotNull = !dataFlowValue.immanentNullability.canBeNull()
val nullableExpectedType = TypeUtils.makeNullable(expectedType)
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.type, nullableExpectedType) &&
(additionalPredicate == null || additionalPredicate(dataFlowValue.type))
) {
if (!immanentlyNotNull && expression != null) {
recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, call, recordExpressionType)
}
return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable)
}
return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, call, recordExpressionType)
}
return null
}
enum class ReceiverSmartCastResult { enum class ReceiverSmartCastResult {
OK, OK,
SMARTCAST_NEEDED_OR_NOT_NULL_EXPECTED SMARTCAST_NEEDED_OR_NOT_NULL_EXPECTED
} }
companion object { companion object {
// REVIEW: make it non-static too?
private fun recordCastOrError( private fun recordCastOrError(
expression: KtExpression, expression: KtExpression,
type: KotlinType, type: KotlinType,
@@ -158,92 +234,5 @@ class SmartCastManager {
trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.text, dataFlowValue.kind.description)) trace.report(SMARTCAST_IMPOSSIBLE.on(expression, type, expression.text, dataFlowValue.kind.description))
} }
} }
fun checkAndRecordPossibleCast(
dataFlowValue: DataFlowValue,
expectedType: KotlinType,
expression: KtExpression?,
c: ResolutionContext<*>,
call: Call?,
recordExpressionType: Boolean
): SmartCastResult? {
return checkAndRecordPossibleCast(dataFlowValue, expectedType, null, expression, c, call, recordExpressionType)
}
fun checkAndRecordPossibleCast(
dataFlowValue: DataFlowValue,
expectedType: KotlinType,
additionalPredicate: ((KotlinType) -> Boolean)?,
expression: KtExpression?,
c: ResolutionContext<*>,
call: Call?,
recordExpressionType: Boolean
): SmartCastResult? {
val calleeExpression = call?.calleeExpression
val expectedTypes = if (c.languageVersionSettings.supportsFeature(LanguageFeature.NewInference))
expectedType.expandIntersectionTypeIfNecessary()
else
listOf(expectedType)
for (possibleType in c.dataFlowInfo.getCollectedTypes(dataFlowValue, c.languageVersionSettings)) {
if (expectedTypes.any { ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, it) } &&
(additionalPredicate == null || additionalPredicate(possibleType))
) {
if (expression != null) {
recordCastOrError(expression, possibleType, c.trace, dataFlowValue, call, recordExpressionType)
} else if (calleeExpression != null && dataFlowValue.isStable) {
val receiver = (dataFlowValue.identifierInfo as? IdentifierInfo.Receiver)?.value
if (receiver is ImplicitReceiver) {
val oldSmartCasts = c.trace[IMPLICIT_RECEIVER_SMARTCAST, calleeExpression]
val newSmartCasts = ImplicitSmartCasts(receiver, possibleType)
if (oldSmartCasts != null) {
val oldType = oldSmartCasts.receiverTypes[receiver]
if (oldType != null && oldType != possibleType) {
throw AssertionError(
"Rewriting key $receiver for implicit smart cast on ${calleeExpression.text}: " +
"was $oldType, now $possibleType"
)
}
}
c.trace.record(IMPLICIT_RECEIVER_SMARTCAST, calleeExpression,
oldSmartCasts?.let { it + newSmartCasts } ?: newSmartCasts)
}
}
return SmartCastResult(possibleType, dataFlowValue.isStable)
}
}
if (!c.dataFlowInfo.getCollectedNullability(dataFlowValue).canBeNull() && !expectedType.isMarkedNullable) {
// Handling cases like:
// fun bar(x: Any) {}
// fun <T : Any?> foo(x: T) {
// if (x != null) {
// bar(x) // Should be allowed with smart cast
// }
// }
//
// It doesn't handled by lower code with getPossibleTypes because smart cast of T after `x != null` is still has same type T.
// But at the same time we're sure that `x` can't be null and just check for such cases manually
// E.g. in case x!! when x has type of T where T is type parameter with nullable upper bounds
// x!! is immanently not null (see DataFlowValueFactory.createDataFlowValue for expression)
val immanentlyNotNull = !dataFlowValue.immanentNullability.canBeNull()
val nullableExpectedType = TypeUtils.makeNullable(expectedType)
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.type, nullableExpectedType) &&
(additionalPredicate == null || additionalPredicate(dataFlowValue.type))
) {
if (!immanentlyNotNull && expression != null) {
recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, call, recordExpressionType)
}
return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable)
}
return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, call, recordExpressionType)
}
return null
}
} }
} }
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.makeNullableTypeIfSaf
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager
import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy
import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant
@@ -69,7 +70,8 @@ class KotlinToResolvedCallTransformer(
private val moduleDescriptor: ModuleDescriptor, private val moduleDescriptor: ModuleDescriptor,
private val dataFlowValueFactory: DataFlowValueFactory, private val dataFlowValueFactory: DataFlowValueFactory,
private val builtIns: KotlinBuiltIns, private val builtIns: KotlinBuiltIns,
private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate private val typeSystemContext: TypeSystemInferenceExtensionContextDelegate,
private val smartCastManager: SmartCastManager
) { ) {
companion object { companion object {
private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC private val REPORT_MISSING_NEW_INFERENCE_DIAGNOSTIC
@@ -471,7 +473,8 @@ class KotlinToResolvedCallTransformer(
newContext, newContext,
completedCallAtom.atom.psiKotlinCall, completedCallAtom.atom.psiKotlinCall,
context.dataFlowValueFactory, context.dataFlowValueFactory,
allDiagnostics allDiagnostics,
smartCastManager
) )
for (diagnostic in allDiagnostics) { for (diagnostic in allDiagnostics) {
@@ -61,6 +61,7 @@ public class DataFlowAnalyzer {
private final LanguageVersionSettings languageVersionSettings; private final LanguageVersionSettings languageVersionSettings;
private final EffectSystem effectSystem; private final EffectSystem effectSystem;
private final DataFlowValueFactory dataFlowValueFactory; private final DataFlowValueFactory dataFlowValueFactory;
private final SmartCastManager smartCastManager;
public DataFlowAnalyzer( public DataFlowAnalyzer(
@NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers, @NotNull Iterable<AdditionalTypeChecker> additionalTypeCheckers,
@@ -70,7 +71,8 @@ public class DataFlowAnalyzer {
@NotNull ExpressionTypingFacade facade, @NotNull ExpressionTypingFacade facade,
@NotNull LanguageVersionSettings languageVersionSettings, @NotNull LanguageVersionSettings languageVersionSettings,
@NotNull EffectSystem effectSystem, @NotNull EffectSystem effectSystem,
@NotNull DataFlowValueFactory factory @NotNull DataFlowValueFactory factory,
@NotNull SmartCastManager smartCastManager
) { ) {
this.additionalTypeCheckers = additionalTypeCheckers; this.additionalTypeCheckers = additionalTypeCheckers;
this.constantExpressionEvaluator = constantExpressionEvaluator; this.constantExpressionEvaluator = constantExpressionEvaluator;
@@ -80,6 +82,7 @@ public class DataFlowAnalyzer {
this.languageVersionSettings = languageVersionSettings; this.languageVersionSettings = languageVersionSettings;
this.effectSystem = effectSystem; this.effectSystem = effectSystem;
this.dataFlowValueFactory = factory; this.dataFlowValueFactory = factory;
this.smartCastManager = smartCastManager;
} }
// NB: use this method only for functions from 'Any' // NB: use this method only for functions from 'Any'
@@ -349,7 +352,7 @@ public class DataFlowAnalyzer {
) { ) {
DataFlowValue dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, expressionType, c); DataFlowValue dataFlowValue = dataFlowValueFactory.createDataFlowValue(expression, expressionType, c);
return SmartCastManager.Companion.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false); return smartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false, null);
} }
public void recordExpectedType(@NotNull BindingTrace trace, @NotNull KtExpression expression, @NotNull KotlinType expectedType) { public void recordExpectedType(@NotNull BindingTrace trace, @NotNull KtExpression expression, @NotNull KotlinType expectedType) {
@@ -133,8 +133,7 @@ sealed class CallTypeAndReceiver<TReceiver : KtElement?, out TCallType : CallTyp
class DOT(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.DOT>(CallType.DOT, receiver) class DOT(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.DOT>(CallType.DOT, receiver)
class SAFE(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.SAFE>(CallType.SAFE, receiver) class SAFE(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.SAFE>(CallType.SAFE, receiver)
class SUPER_MEMBERS(receiver: KtSuperExpression) : CallTypeAndReceiver<KtSuperExpression, CallType.SUPER_MEMBERS>( class SUPER_MEMBERS(receiver: KtSuperExpression) : CallTypeAndReceiver<KtSuperExpression, CallType.SUPER_MEMBERS>(
CallType.SUPER_MEMBERS, CallType.SUPER_MEMBERS, receiver
receiver
) )
class INFIX(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.INFIX>(CallType.INFIX, receiver) class INFIX(receiver: KtExpression) : CallTypeAndReceiver<KtExpression, CallType.INFIX>(CallType.INFIX, receiver)
@@ -275,8 +274,8 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext) val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext)
receiverValueTypes( receiverValueTypes(
receiverValue, lhs.dataFlowInfo, bindingContext, receiverValue, lhs.dataFlowInfo, bindingContext,
moduleDescriptor, stableSmartCastsOnly, languageVersionSettings, moduleDescriptor, stableSmartCastsOnly,
resolutionFacade.frontendService() resolutionFacade
).map { ReceiverType(it, 0) } ).map { ReceiverType(it, 0) }
} }
} }
@@ -339,8 +338,8 @@ fun CallTypeAndReceiver<*, *>.receiverTypesWithIndex(
fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) { fun addReceiverType(receiverValue: ReceiverValue, implicit: Boolean) {
val types = receiverValueTypes( val types = receiverValueTypes(
receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly, languageVersionSettings, receiverValue, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly,
resolutionFacade.frontendService() resolutionFacade
) )
types.mapTo(result) { type -> ReceiverType(type, receiverIndex, receiverValue.takeIf { implicit }) } types.mapTo(result) { type -> ReceiverType(type, receiverIndex, receiverValue.takeIf { implicit }) }
@@ -362,12 +361,14 @@ private fun receiverValueTypes(
bindingContext: BindingContext, bindingContext: BindingContext,
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
stableSmartCastsOnly: Boolean, stableSmartCastsOnly: Boolean,
languageVersionSettings: LanguageVersionSettings, resolutionFacade: ResolutionFacade
dataFlowValueFactory: DataFlowValueFactory
): List<KotlinType> { ): List<KotlinType> {
val languageVersionSettings = resolutionFacade.frontendService<LanguageVersionSettings>()
val dataFlowValueFactory = resolutionFacade.frontendService<DataFlowValueFactory>()
val smartCastManager = resolutionFacade.frontendService<SmartCastManager>()
val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor) val dataFlowValue = dataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor)
return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" receiver value to mark members grayed return if (dataFlowValue.isStable || !stableSmartCastsOnly) { // we don't include smart cast receiver types for "unstable" receiver value to mark members grayed
SmartCastManager().getSmartCastVariantsWithLessSpecificExcluded( smartCastManager.getSmartCastVariantsWithLessSpecificExcluded(
receiverValue, receiverValue,
bindingContext, bindingContext,
moduleDescriptor, moduleDescriptor,