More precise diagnostics of smart cast impossible #KT-7240 Fixed

This commit is contained in:
Mikhail Glukhikh
2015-11-02 17:56:31 +03:00
parent 16a8e8f6f0
commit 41ebfd025e
31 changed files with 94 additions and 73 deletions
@@ -475,7 +475,7 @@ public class CandidateResolver(
val bindingContext = trace.bindingContext
val receiverValue = DataFlowValueFactory.createDataFlowValue(receiverArgument, bindingContext, scope.ownerDescriptor)
if (safeAccess && !dataFlowInfo.getNullability(receiverValue).canBeNull()) {
if (safeAccess && !dataFlowInfo.getPredictableNullability(receiverValue).canBeNull()) {
tracing.unnecessarySafeCall(trace, receiverArgument.type)
}
@@ -37,9 +37,19 @@ public interface DataFlowInfo {
@NotNull
SetMultimap<DataFlowValue, KotlinType> getCompleteTypeInfo();
/**
* Returns collected nullability for the given value, NOT taking its predictability into account.
*/
@NotNull
Nullability getNullability(@NotNull DataFlowValue key);
/**
* Returns collected nullability for the given value if it's predictable.
* Otherwise basic value nullability is returned
*/
@NotNull
Nullability getPredictableNullability(@NotNull DataFlowValue key);
/**
* IMPORTANT: by default, the original (native) type for this value
* are NOT included. So it's quite possible to get an empty set here.
@@ -111,7 +111,18 @@ import static org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability.NOT_NULL
@Override
@NotNull
public Nullability getNullability(@NotNull DataFlowValue key) {
if (!key.isPredictable()) return key.getImmanentNullability();
return getNullability(key, false);
}
@Override
@NotNull
public Nullability getPredictableNullability(@NotNull DataFlowValue key) {
return getNullability(key, true);
}
@NotNull
private Nullability getNullability(@NotNull DataFlowValue key, boolean predictableOnly) {
if (predictableOnly && !key.isPredictable()) return key.getImmanentNullability();
Nullability nullability = nullabilityInfo.get(key);
return nullability != null ? nullability :
parent != null ? parent.getNullability(key) :
@@ -123,7 +134,6 @@ import static org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability.NOT_NULL
@NotNull DataFlowValue value,
@NotNull Nullability nullability
) {
if (!value.isPredictable()) return false;
map.put(value, nullability);
return nullability != getNullability(value);
}
@@ -892,7 +892,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.getNullability(dataFlowValue).canBeNull();
return !context.dataFlowInfo.getPredictableNullability(dataFlowValue).canBeNull();
}
/**
@@ -1191,7 +1191,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
DataFlowInfo rightDataFlowInfo = resolvedCall.getDataFlowInfoForArguments().getResultInfo();
// left argument is considered not-null if it's not-null also in right part or if we have jump in right part
if ((rightType != null && KotlinBuiltIns.isNothingOrNullableNothing(rightType) && !rightType.isMarkedNullable())
|| !rightDataFlowInfo.getNullability(leftValue).canBeNull()) {
|| !rightDataFlowInfo.getPredictableNullability(leftValue).canBeNull()) {
dataFlowInfo = dataFlowInfo.disequate(leftValue, DataFlowValue.nullValue(components.builtIns));
}
}
@@ -1298,7 +1298,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
new Function1<DataFlowValue, Nullability>() {
@Override
public Nullability invoke(DataFlowValue value) {
return context.dataFlowInfo.getNullability(value);
return context.dataFlowInfo.getPredictableNullability(value);
}
});
}