Smart cast impossible on when subject is no more recorded #KT-10061 Fixed
This commit is contained in:
@@ -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) {
|
||||
|
||||
+11
-6
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user