Smart cast impossible on when subject is no more recorded #KT-10061 Fixed

This commit is contained in:
Mikhail Glukhikh
2015-11-18 14:18:04 +03:00
parent 58dc88dd2c
commit 3a4f6d8226
7 changed files with 70 additions and 11 deletions
@@ -207,8 +207,8 @@ public class DataFlowAnalyzer {
return expressionType;
}
KotlinType possibleType = checkPossibleCast(expressionType, expression, c);
if (possibleType != null) return possibleType;
SmartCastResult castResult = checkPossibleCast(expressionType, expression, c);
if (castResult != null) return castResult.getResultType();
c.trace.report(TYPE_MISMATCH.on(expression, c.expectedType, expressionType));
if (hasError != null) hasError.set(true);
@@ -245,15 +245,14 @@ public class DataFlowAnalyzer {
}
@Nullable
public KotlinType checkPossibleCast(
public SmartCastResult checkPossibleCast(
@NotNull KotlinType expressionType,
@NotNull KtExpression expression,
@NotNull ResolutionContext c
) {
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c);
SmartCastResult result = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false);
return result != null ? result.getResultType() : null;
return SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, null, false);
}
public void recordExpectedType(@NotNull BindingTrace trace, @NotNull KtExpression expression, @NotNull KotlinType expectedType) {
@@ -25,13 +25,11 @@ import org.jetbrains.kotlin.cfg.WhenChecker;
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.PossiblyBareType;
import org.jetbrains.kotlin.resolve.TypeResolutionContext;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastResult;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.scopes.LexicalWritableScope;
import org.jetbrains.kotlin.types.*;
@@ -92,8 +90,15 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
subjectType = typeInfo.getType();
assert subjectType != null;
if (TypeUtils.isNullableType(subjectType) && !WhenChecker.containsNullCase(expression, context.trace)) {
ExpressionTypingContext subjectContext = context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType));
components.dataFlowAnalyzer.checkPossibleCast(subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext);
TemporaryBindingTrace trace = TemporaryBindingTrace.create(context.trace, "Temporary trace for when subject nullability");
ExpressionTypingContext subjectContext =
context.replaceExpectedType(TypeUtils.makeNotNullable(subjectType)).replaceBindingTrace(trace);
SmartCastResult castResult = components.dataFlowAnalyzer.checkPossibleCast(
subjectType, KtPsiUtil.safeDeparenthesize(subjectExpression), subjectContext
);
if (castResult != null && castResult.isCorrect()) {
trace.commit();
}
}
context = context.replaceDataFlowInfo(typeInfo.getDataFlowInfo());
}
@@ -0,0 +1,10 @@
// See KT-10061
class My {
val x: Int? get() = 42
}
fun foo(my: My) {
my.x!!
when (my.x) { }
}
@@ -0,0 +1,11 @@
package
public fun foo(/*0*/ my: My): kotlin.Unit
public final class My {
public constructor My()
public final val x: kotlin.Int?
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,11 @@
// See KT-10061
// FILE: My.java
public class My {
String getSomething() { return "xyz"; }
}
// FILE: My.kt
fun foo(my: My) {
my.something!!
when (my.something) { }
}
@@ -0,0 +1,11 @@
package
public fun foo(/*0*/ my: My): kotlin.Unit
public open class My {
public constructor My()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public/*package*/ open fun getSomething(): kotlin.String!
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -14922,6 +14922,18 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("whenSubjectImpossible.kt")
public void testWhenSubjectImpossible() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossible.kt");
doTest(fileName);
}
@TestMetadata("whenSubjectImpossibleJava.kt")
public void testWhenSubjectImpossibleJava() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/whenSubjectImpossibleJava.kt");
doTest(fileName);
}
@TestMetadata("compiler/testData/diagnostics/tests/smartCasts/inference")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)