diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/RuntimeAssertions.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/RuntimeAssertions.kt index ba3a302bf1f..0976029a87f 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/RuntimeAssertions.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/RuntimeAssertions.kt @@ -81,7 +81,7 @@ object RuntimeAssertionsTypeChecker : AdditionalTypeChecker { expressionType, object : RuntimeAssertionInfo.DataFlowExtras { override val canBeNull: Boolean - get() = c.dataFlowInfo.getPredictableNullability(dataFlowValue).canBeNull() + get() = c.dataFlowInfo.getStableNullability(dataFlowValue).canBeNull() override val possibleTypes: Set get() = c.dataFlowInfo.getCollectedTypes(dataFlowValue) override val presentableText: String diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt index 0b4602b808b..1cb0f990a09 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/ProtectedSyntheticExtensionCallChecker.kt @@ -46,7 +46,7 @@ object ProtectedSyntheticExtensionCallChecker : CallChecker { if (resolvedCall.dispatchReceiver != null && resolvedCall.extensionReceiver !is ReceiverValue) return val receiverValue = resolvedCall.extensionReceiver as ReceiverValue - val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getPredictableTypes( + val receiverTypes = listOf(receiverValue.type) + context.dataFlowInfo.getStableTypes( DataFlowValueFactory.createDataFlowValue(receiverValue, context.trace.bindingContext, context.scope.ownerDescriptor) ) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt index 4fa9e588f20..95a4ab750dc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.kt @@ -319,7 +319,7 @@ class CallExpressionResolver( var initialDataFlowInfoForArguments = context.dataFlowInfo val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) } val receiverCanBeNull = receiverDataFlowValue != null && - initialDataFlowInfoForArguments.getPredictableNullability(receiverDataFlowValue).canBeNull() + initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull() if (receiverDataFlowValue != null && element.safe) { // Additional "receiver != null" information should be applied if we consider a safe call if (receiverCanBeNull) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt index 4ef5323e561..9c056672cfa 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CandidateResolver.kt @@ -506,7 +506,7 @@ class CandidateResolver( val outerCallReceiver = call.outerCall.explicitReceiver if (outerCallReceiver != call.explicitReceiver && outerCallReceiver is ReceiverValue) { val outerReceiverDataFlowValue = DataFlowValueFactory.createDataFlowValue(outerCallReceiver, this) - val outerReceiverNullability = dataFlowInfo.getPredictableNullability(outerReceiverDataFlowValue) + val outerReceiverNullability = dataFlowInfo.getStableNullability(outerReceiverDataFlowValue) if (outerReceiverNullability.canBeNull() && !TypeUtils.isNullableType(expectedReceiverParameterType)) { nullableImplicitInvokeReceiver = true receiverArgumentType = TypeUtils.makeNullable(receiverArgumentType) @@ -515,7 +515,7 @@ class CandidateResolver( } val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, this) - val nullability = dataFlowInfo.getPredictableNullability(dataFlowValue) + val nullability = dataFlowInfo.getStableNullability(dataFlowValue) val expression = (receiverArgument as? ExpressionReceiver)?.expression if (nullability.canBeNull() && !nullability.canBeNonNull()) { if (!TypeUtils.isNullableType(expectedReceiverParameterType)) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 981d26c2605..9836a3f0202 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -195,7 +195,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes if (deparenthesizedArgument == null || type == null) return type val dataFlowValue = DataFlowValueFactory.createDataFlowValue(deparenthesizedArgument, type, context) - if (!dataFlowValue.isPredictable) return type + if (!dataFlowValue.isStable) return type val possibleTypes = context.dataFlowInfo.getCollectedTypes(dataFlowValue) if (possibleTypes.isEmpty()) return type diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt index 0abdb9bb8e7..e944e95d6f7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt @@ -82,7 +82,7 @@ private fun ResolvedCall<*>.hasSafeNullableReceiver(context: CallResolutionConte if (!call.isSafeCall()) return false val receiverValue = getExplicitReceiverValue()?.let { DataFlowValueFactory.createDataFlowValue(it, context) } ?: return false - return context.dataFlowInfo.getPredictableNullability(receiverValue).canBeNull() + return context.dataFlowInfo.getStableNullability(receiverValue).canBeNull() } fun ResolvedCall<*>.makeNullableTypeIfSafeReceiver(type: KotlinType?, context: CallResolutionContext<*>) = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.kt index c3d888307d9..5f94a011779 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowInfo.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.resolve.calls.smartcasts -import com.google.common.collect.ImmutableMap import com.google.common.collect.SetMultimap import org.jetbrains.kotlin.types.KotlinType @@ -31,18 +30,18 @@ interface DataFlowInfo { val completeTypeInfo: SetMultimap /** - * Returns collected nullability for the given value, NOT taking its predictability into account. + * Returns collected nullability for the given value, NOT taking its stability into account. */ fun getCollectedNullability(key: DataFlowValue): Nullability /** - * Returns collected nullability for the given value if it's predictable. + * Returns collected nullability for the given value if it's stable. * Otherwise basic value nullability is returned */ - fun getPredictableNullability(key: DataFlowValue): Nullability + fun getStableNullability(key: DataFlowValue): Nullability /** - * Returns possible types for the given value, NOT taking its predictability into account. + * Returns possible types for the given value, NOT taking its stability into account. * * IMPORTANT: by default, the original (native) type for this value * are NOT included. So it's quite possible to get an empty set here. @@ -50,13 +49,13 @@ interface DataFlowInfo { fun getCollectedTypes(key: DataFlowValue): Set /** - * Returns possible types for the given value if it's predictable. + * Returns possible types for the given value if it's stable. * Otherwise, basic value type is returned. * * IMPORTANT: by default, the original (native) type for this value * are NOT included. So it's quite possible to get an empty set here. */ - fun getPredictableTypes(key: DataFlowValue): Set + fun getStableTypes(key: DataFlowValue): Set /** * Call this function to clear all data flow information about diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt index 8944fb76091..66ed5e1d7c8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValueFactory.kt @@ -316,25 +316,25 @@ object DataFlowValueFactory { if (!variableDescriptor.isVar) return STABLE_VALUE if (variableDescriptor is SyntheticFieldDescriptor) return MUTABLE_PROPERTY - // Local variable classification: PREDICTABLE or UNPREDICTABLE + // Local variable classification: STABLE or CAPTURED val preliminaryVisitor = PreliminaryDeclarationVisitor.getVisitorByVariable(variableDescriptor, bindingContext) - ?: return UNPREDICTABLE_VARIABLE - // A case when we just analyse an expression alone: counts as unpredictable + // A case when we just analyse an expression alone: counts as captured + ?: return CAPTURED_VARIABLE // Analyze who writes variable - // If there is no writer: predictable + // If there is no writer: stable val writers = preliminaryVisitor.writers(variableDescriptor) - if (writers.isEmpty()) return PREDICTABLE_VARIABLE + if (writers.isEmpty()) return STABLE_VARIABLE - // If access element is inside closure: unpredictable + // If access element is inside closure: captured val variableContainingDeclaration = getVariableContainingDeclaration(variableDescriptor) - if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) return UNPREDICTABLE_VARIABLE + if (isAccessedInsideClosure(variableContainingDeclaration, bindingContext, accessElement)) return CAPTURED_VARIABLE - // Otherwise, predictable iff considered position is BEFORE all writers except declarer itself + // Otherwise, stable iff considered position is BEFORE all writers except declarer itself return if (isAccessedBeforeAllClosureWriters(variableContainingDeclaration, writers, bindingContext, accessElement)) - PREDICTABLE_VARIABLE + STABLE_VARIABLE else - UNPREDICTABLE_VARIABLE + CAPTURED_VARIABLE } /** diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt index 4088d1e0178..0148d244cf8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DelegatingDataFlowInfo.kt @@ -75,10 +75,10 @@ internal class DelegatingDataFlowInfo private constructor( override fun getCollectedNullability(key: DataFlowValue) = getNullability(key, false) - override fun getPredictableNullability(key: DataFlowValue) = getNullability(key, true) + override fun getStableNullability(key: DataFlowValue) = getNullability(key, true) - private fun getNullability(key: DataFlowValue, predictableOnly: Boolean) = - if (predictableOnly && !key.isPredictable) { + private fun getNullability(key: DataFlowValue, stableOnly: Boolean) = + if (stableOnly && !key.isStable) { key.immanentNullability } else { @@ -132,10 +132,10 @@ internal class DelegatingDataFlowInfo private constructor( return enrichedTypes } - override fun getPredictableTypes(key: DataFlowValue) = getPredictableTypes(key, true) + override fun getStableTypes(key: DataFlowValue) = getStableTypes(key, true) - private fun getPredictableTypes(key: DataFlowValue, enrichWithNotNull: Boolean) = - if (!key.isPredictable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull) + private fun getStableTypes(key: DataFlowValue, enrichWithNotNull: Boolean) = + if (!key.isStable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull) /** * Call this function to clear all data flow information about @@ -151,11 +151,11 @@ internal class DelegatingDataFlowInfo private constructor( override fun assign(a: DataFlowValue, b: DataFlowValue): DataFlowInfo { val nullability = Maps.newHashMap() - val nullabilityOfB = getPredictableNullability(b) + val nullabilityOfB = getStableNullability(b) putNullability(nullability, a, nullabilityOfB, affectReceiver = false) val newTypeInfo = newTypeInfo() - var typesForB = getPredictableTypes(b) + var typesForB = getStableTypes(b) // Own type of B must be recorded separately, e.g. for a constant // But if its type is the same as A, there is no reason to do it // because own type is not saved in this set @@ -170,8 +170,8 @@ internal class DelegatingDataFlowInfo private constructor( override fun equate(a: DataFlowValue, b: DataFlowValue, sameTypes: Boolean): DataFlowInfo { val builder = Maps.newHashMap() - val nullabilityOfA = getPredictableNullability(a) - val nullabilityOfB = getPredictableNullability(b) + val nullabilityOfA = getStableNullability(a) + val nullabilityOfB = getStableNullability(b) var changed = putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB)) or putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA)) @@ -179,8 +179,8 @@ internal class DelegatingDataFlowInfo private constructor( // NB: == has no guarantees of type equality, see KT-11280 for the example val newTypeInfo = newTypeInfo() if (sameTypes) { - newTypeInfo.putAll(a, getPredictableTypes(b, false)) - newTypeInfo.putAll(b, getPredictableTypes(a, false)) + newTypeInfo.putAll(a, getStableTypes(b, false)) + newTypeInfo.putAll(b, getStableTypes(a, false)) if (a.type != b.type) { // To avoid recording base types of own type if (!a.type.isSubtypeOf(b.type)) { @@ -226,8 +226,8 @@ internal class DelegatingDataFlowInfo private constructor( override fun disequate(a: DataFlowValue, b: DataFlowValue): DataFlowInfo { val builder = Maps.newHashMap() - val nullabilityOfA = getPredictableNullability(a) - val nullabilityOfB = getPredictableNullability(b) + val nullabilityOfA = getStableNullability(a) + val nullabilityOfB = getStableNullability(b) val changed = putNullability(builder, a, nullabilityOfA.refine(nullabilityOfB.invert())) or putNullability(builder, b, nullabilityOfB.refine(nullabilityOfA.invert())) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt index ac1aa4fc898..895ff44e502 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/smartcasts/SmartCastManager.kt @@ -116,7 +116,7 @@ class SmartCastManager { recordExpressionType: Boolean ) { if (KotlinBuiltIns.isNullableNothing(type)) return - if (dataFlowValue.isPredictable) { + if (dataFlowValue.isStable) { trace.record(SMARTCAST, expression, type) if (recordExpressionType) { //TODO @@ -154,10 +154,10 @@ class SmartCastManager { if (expression != null) { recordCastOrError(expression, possibleType, c.trace, dataFlowValue, recordExpressionType) } - else if (calleeExpression != null && dataFlowValue.isPredictable) { + else if (calleeExpression != null && dataFlowValue.isStable) { c.trace.record(IMPLICIT_RECEIVER_SMARTCAST, calleeExpression, possibleType) } - return SmartCastResult(possibleType, dataFlowValue.isPredictable) + return SmartCastResult(possibleType, dataFlowValue.isStable) } } @@ -183,7 +183,7 @@ class SmartCastManager { recordCastOrError(expression, dataFlowValue.type, c.trace, dataFlowValue, recordExpressionType) } - return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isPredictable) + return SmartCastResult(dataFlowValue.type, immanentlyNotNull || dataFlowValue.isStable) } return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, calleeExpression, recordExpressionType) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt index 1a3af3711a2..7286e7508cd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ScopeTowerImpl.kt @@ -58,7 +58,7 @@ private class DataFlowDecoratorImpl(private val resolutionContext: ResolutionCon override fun getDataFlowValue(receiver: ReceiverValue): DataFlowValue = getSmartCastInfo(receiver).dataFlowValue - override fun isStableReceiver(receiver: ReceiverValue): Boolean = getSmartCastInfo(receiver).dataFlowValue.isPredictable + override fun isStableReceiver(receiver: ReceiverValue): Boolean = getSmartCastInfo(receiver).dataFlowValue.isStable override fun getSmartCastTypes(receiver: ReceiverValue): Set = getSmartCastInfo(receiver).possibleTypes diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index de672415502..ab5db78f9f1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -142,7 +142,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { // Receivers are normally analyzed at resolve, with an exception of KT-10175 if (type != null && !type.isError() && !isLValueOrUnsafeReceiver(expression)) { DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context); - Nullability nullability = context.dataFlowInfo.getPredictableNullability(dataFlowValue); + Nullability nullability = context.dataFlowInfo.getStableNullability(dataFlowValue); if (!nullability.canBeNonNull() && nullability.canBeNull()) { if (isDangerousWithNull(expression, context)) { context.trace.report(ALWAYS_NULL.on(expression)); @@ -878,7 +878,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { private static boolean isKnownToBeNotNull(KtExpression expression, KotlinType jetType, ExpressionTypingContext context) { DataFlowValue dataFlowValue = createDataFlowValue(expression, jetType, context); - return !context.dataFlowInfo.getPredictableNullability(dataFlowValue).canBeNull(); + return !context.dataFlowInfo.getStableNullability(dataFlowValue).canBeNull(); } /** @@ -1221,7 +1221,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { boolean jumpInRight = KotlinBuiltIns.isNothing(rightType); DataFlowValue nullValue = DataFlowValue.nullValue(components.builtIns); // left argument is considered not-null if it's not-null also in right part or if we have jump in right part - if (jumpInRight || !rightDataFlowInfo.getPredictableNullability(leftValue).canBeNull()) { + if (jumpInRight || !rightDataFlowInfo.getStableNullability(leftValue).canBeNull()) { dataFlowInfo = dataFlowInfo.disequate(leftValue, nullValue); if (left instanceof KtBinaryExpressionWithTypeRHS) { dataFlowInfo = establishSubtypingForTypeRHS((KtBinaryExpressionWithTypeRHS) left, dataFlowInfo, context); @@ -1360,7 +1360,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { new Function1() { @Override public Nullability invoke(DataFlowValue value) { - return context.dataFlowInfo.getPredictableNullability(value); + return context.dataFlowInfo.getStableNullability(value); } }); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java index 589a62ef598..14701d604a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DataFlowAnalyzer.java @@ -341,7 +341,7 @@ public class DataFlowAnalyzer { ) { DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, c); Collection possibleTypes = Sets.newHashSet(type); - possibleTypes.addAll(dataFlowInfo.getPredictableTypes(dataFlowValue)); + possibleTypes.addAll(dataFlowInfo.getStableTypes(dataFlowValue)); return possibleTypes; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt index 9d3d9ecbb89..993be46b376 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PreliminaryLoopVisitor.kt @@ -34,9 +34,9 @@ class PreliminaryLoopVisitor private constructor() : AssignedVariablesSearcher() val nullabilityMap = resultFlowInfo.completeNullabilityInfo val valueSetToClear = LinkedHashSet() for (value in nullabilityMap.keys) { - // Only predictable variables are under interest here + // Only stable variables are under interest here val identifierInfo = value.identifierInfo - if (value.kind == DataFlowValue.Kind.PREDICTABLE_VARIABLE && identifierInfo is IdentifierInfo.Variable) { + if (value.kind == DataFlowValue.Kind.STABLE_VARIABLE && identifierInfo is IdentifierInfo.Variable) { val variableDescriptor = identifierInfo.variable if (variableDescriptor is LocalVariableDescriptor && hasWriters(variableDescriptor)) { valueSetToClear.add(value) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt index 35d9d8e34e9..840a2965c43 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/DataFlowValue.kt @@ -38,7 +38,7 @@ class DataFlowValue(val identifierInfo: IdentifierInfo, // Local value, or parameter, or private / internal member value without open / custom getter, // or protected / public member value from the same module without open / custom getter // Smart casts are completely safe - STABLE_VALUE("stable"), + STABLE_VALUE("stable val"), // Member value with open / custom getter // Smart casts are not safe PROPERTY_WITH_GETTER("custom getter", "property that has open or custom getter"), @@ -47,10 +47,10 @@ class DataFlowValue(val identifierInfo: IdentifierInfo, ALIEN_PUBLIC_PROPERTY("alien public", "public API property declared in different module"), // Local variable not yet captured by a changing closure // Smart casts are safe but possible changes in loops / closures ahead must be taken into account - PREDICTABLE_VARIABLE("predictable", "local variable that can be changed since the check in a loop"), + STABLE_VARIABLE("stable var", "local variable that can be changed since the check in a loop"), // Local variable already captured by a changing closure // Smart casts are not safe - UNPREDICTABLE_VARIABLE("unpredictable", "local variable that is captured by a changing closure"), + CAPTURED_VARIABLE("captured var", "local variable that is captured by a changing closure"), // Member variable regardless of its visibility // Smart casts are not safe MUTABLE_PROPERTY("member", "mutable property that could have been changed by this time"), @@ -59,17 +59,13 @@ class DataFlowValue(val identifierInfo: IdentifierInfo, OTHER("other", "complex expression"); override fun toString() = str - - fun isStable() = this == STABLE_VALUE } /** - * Both stable values and predictable local variables are considered "predictable". - * Predictable means here we do not expect some sudden change of their values, + * Stable means here we do not expect some sudden change of their values, * like accessing mutable properties in another thread, so smart casts can be used safely. */ - val isPredictable = (kind == Kind.STABLE_VALUE || kind == Kind.PREDICTABLE_VARIABLE) - @JvmName("isPredictable") get + val isStable = (kind == Kind.STABLE_VALUE || kind == Kind.STABLE_VARIABLE) override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt index 49098b4b1ad..7a8adcaf8e6 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/smartcasts/IdentifierInfo.kt @@ -72,7 +72,7 @@ interface IdentifierInfo { val safe: Boolean, val receiverType: KotlinType? ) : IdentifierInfo { - override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind.isStable()) selectorInfo.kind else OTHER + override val kind: DataFlowValue.Kind get() = if (receiverInfo.kind == STABLE_VALUE) selectorInfo.kind else OTHER override fun equals(other: Any?) = other is Qualified && receiverInfo == other.receiverInfo && selectorInfo == other.selectorInfo diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index 3a19494316c..1402853beae 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -186,7 +186,7 @@ class ReferenceVariantsHelper( listOf(useReceiverType) } else { - callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)!! + callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)!! } descriptors.processAll(implicitReceiverTypes, explicitReceiverTypes, resolutionScope, callType, kindFilter, nameFilter) @@ -244,7 +244,7 @@ class ReferenceVariantsHelper( listOf(useReceiverType) } else { - callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false)!! + callTypeAndReceiver.receiverTypes(bindingContext, contextElement, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false)!! } val constructorFilter = { descriptor: ClassDescriptor -> if (isStatic) true else descriptor.isInner } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt index 2331e7cef35..33137799d32 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/CallType.kt @@ -213,7 +213,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypes( contextElement: PsiElement, moduleDescriptor: ModuleDescriptor, resolutionFacade: ResolutionFacade, - predictableSmartCastsOnly: Boolean + stableSmartCastsOnly: Boolean ): Collection? { val receiverExpression: KtExpression? when (this) { @@ -225,7 +225,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypes( is DoubleColonLHS.Expression -> { val receiverValue = ExpressionReceiver.create(receiver, lhs.type, bindingContext) - return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, moduleDescriptor, predictableSmartCastsOnly) + return receiverValueTypes(receiverValue, lhs.dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly) } } } @@ -281,7 +281,7 @@ fun CallTypeAndReceiver<*, *>.receiverTypes( val dataFlowInfo = bindingContext.getDataFlowInfo(contextElement) return receiverValues.flatMap { - receiverValueTypes(it, dataFlowInfo, bindingContext, moduleDescriptor, predictableSmartCastsOnly) + receiverValueTypes(it, dataFlowInfo, bindingContext, moduleDescriptor, stableSmartCastsOnly) } } @@ -290,10 +290,10 @@ private fun receiverValueTypes( dataFlowInfo: DataFlowInfo, bindingContext: BindingContext, moduleDescriptor: ModuleDescriptor, - predictableSmartCastsOnly: Boolean + stableSmartCastsOnly: Boolean ): List { val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, bindingContext, moduleDescriptor) - return if (dataFlowValue.isPredictable || !predictableSmartCastsOnly) { // we don't include smart cast receiver types for "unpredictable" 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(receiverValue, bindingContext, moduleDescriptor, dataFlowInfo) } else { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 778a8ccb50c..d8bf598eb0f 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -439,7 +439,7 @@ abstract class CompletionSession( var receiverTypes = callTypeAndReceiver.receiverTypes( bindingContext, nameExpression, moduleDescriptor, resolutionFacade, - predictableSmartCastsOnly = true /* we don't include smart cast receiver types for "unpredictable" receiver value to mark members grayed */) + stableSmartCastsOnly = true /* we don't include smart cast receiver types for "unstable" receiver value to mark members grayed */) if (callTypeAndReceiver is CallTypeAndReceiver.SAFE || isDebuggerContext) { receiverTypes = receiverTypes?.map { it.makeNotNullable() } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt index f6f0be54658..652092bfde5 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/KotlinIndicesHelper.kt @@ -132,7 +132,7 @@ class KotlinIndicesHelper( bindingContext: BindingContext, nameFilter: (String) -> Boolean ): Collection { - val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, predictableSmartCastsOnly = false) + val receiverTypes = callTypeAndReceiver.receiverTypes(bindingContext, position, moduleDescriptor, resolutionFacade, stableSmartCastsOnly = false) ?: return emptyList() return getCallableTopLevelExtensions(callTypeAndReceiver, receiverTypes, nameFilter) } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt index 6540cc92361..293a731d229 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/SurroundWithNullCheckFix.kt @@ -67,7 +67,7 @@ class SurroundWithNullCheckFix( else -> return null } as? KtReferenceExpression ?: return null - if (!nullableExpression.isPredictable()) return null + if (!nullableExpression.isStable()) return null return SurroundWithNullCheckFix(expression, nullableExpression) } @@ -80,7 +80,7 @@ class SurroundWithNullCheckFix( val forExpression = nullableExpression.parent?.parent as? KtForExpression ?: return null if (forExpression.parent !is KtBlockExpression) return null - if (!nullableExpression.isPredictable()) return null + if (!nullableExpression.isStable()) return null return SurroundWithNullCheckFix(forExpression, nullableExpression) } @@ -97,16 +97,16 @@ class SurroundWithNullCheckFix( if (!isNullabilityMismatch(expected = typeMismatch.a, actual = typeMismatch.b)) return null - if (!nullableExpression.isPredictable()) return null + if (!nullableExpression.isStable()) return null return SurroundWithNullCheckFix(call, nullableExpression) } } } -private fun KtExpression.isPredictable(): Boolean { +private fun KtExpression.isStable(): Boolean { val context = this.analyze() val nullableType = this.getType(context) ?: return false val containingDescriptor = this.getResolutionScope(context, this.getResolutionFacade()).ownerDescriptor - return DataFlowValueFactory.createDataFlowValue(this, nullableType, context, containingDescriptor).isPredictable + return DataFlowValueFactory.createDataFlowValue(this, nullableType, context, containingDescriptor).isStable } diff --git a/idea/tests/org/jetbrains/kotlin/DataFlowValueRenderingTest.kt b/idea/tests/org/jetbrains/kotlin/DataFlowValueRenderingTest.kt index 085b1a87bc3..8968e4aafdf 100644 --- a/idea/tests/org/jetbrains/kotlin/DataFlowValueRenderingTest.kt +++ b/idea/tests/org/jetbrains/kotlin/DataFlowValueRenderingTest.kt @@ -47,7 +47,7 @@ abstract class AbstractDataFlowValueRenderingTest: KotlinLightCodeInsightFixture private fun DataFlowValue.render() = // If it is not a stable identifier, there's no point in rendering it - if (!isPredictable) null + if (!isStable) null else identifierInfo.render() override fun getTestDataPath() : String {