diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 5ce5701c3b4..2bb2bdebfdd 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -739,7 +739,6 @@ public interface Errors { DiagnosticFactory1 EXPECTED_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 ASSIGNMENT_TYPE_MISMATCH = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 TYPE_MISMATCH_IN_FOR_LOOP = DiagnosticFactory2.create(ERROR); - DiagnosticFactory1 TYPE_MISMATCH_IN_CONDITION = DiagnosticFactory1.create(ERROR); DiagnosticFactory3 RESULT_TYPE_MISMATCH = DiagnosticFactory3.create(ERROR); DiagnosticFactory0 TYPE_MISMATCH_IN_RANGE = DiagnosticFactory0.create(ERROR, WHEN_CONDITION_IN_RANGE); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index f066433affe..f37d19ef2ca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -540,7 +540,6 @@ public class DefaultErrorMessages { MAP.put(TYPE_MISMATCH_IN_FOR_LOOP, "The loop iterates over values of type {0} but the parameter is declared to be {1}", RENDER_TYPE, RENDER_TYPE); - MAP.put(TYPE_MISMATCH_IN_CONDITION, "Condition must be of type Boolean, but is of type {0}", RENDER_TYPE); MAP.put(INCOMPATIBLE_TYPES, "Incompatible types: {0} and {1}", RENDER_TYPE, RENDER_TYPE); MAP.put(IMPLICIT_NOTHING_RETURN_TYPE, "'Nothing' return type needs to be specified explicitly"); MAP.put(IMPLICIT_NOTHING_PROPERTY_TYPE, "'Nothing' property type needs to be specified explicitly"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java index 0b340ba6e4e..4d1a6fe9ab6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ControlStructureTypingVisitor.java @@ -69,15 +69,11 @@ public class ControlStructureTypingVisitor extends ExpressionTypingVisitor { @NotNull private DataFlowInfo checkCondition(@NotNull LexicalScope scope, @Nullable KtExpression condition, ExpressionTypingContext context) { if (condition != null) { - KotlinTypeInfo typeInfo = facade.getTypeInfo(condition, context.replaceScope(scope) - .replaceExpectedType(components.builtIns.getBooleanType()).replaceContextDependency(INDEPENDENT)); - KotlinType conditionType = typeInfo.getType(); + ExpressionTypingContext conditionContext = context.replaceScope(scope) + .replaceExpectedType(components.builtIns.getBooleanType()).replaceContextDependency(INDEPENDENT); + KotlinTypeInfo typeInfo = facade.getTypeInfo(condition, conditionContext); - if (conditionType != null && !components.builtIns.isBooleanOrSubtype(conditionType)) { - context.trace.report(TYPE_MISMATCH_IN_CONDITION.on(condition, conditionType)); - } - - return typeInfo.getDataFlowInfo(); + return components.dataFlowAnalyzer.checkType(typeInfo, condition, conditionContext).getDataFlowInfo(); } return context.dataFlowInfo; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt index c63674c7ad8..090544c1553 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.kt @@ -322,10 +322,8 @@ class PatternMatchingTypingVisitor internal constructor(facade: ExpressionTyping newContext = newContext.replaceDataFlowInfo(typeInfo.dataFlowInfo) if (conditionExpected) { val booleanType = components.builtIns.booleanType - if (!KotlinTypeChecker.DEFAULT.equalTypes(booleanType, type)) { - newContext.trace.report(TYPE_MISMATCH_IN_CONDITION.on(expression, type)) - } - else { + val checkedTypeInfo = components.dataFlowAnalyzer.checkType(typeInfo, expression, newContext.replaceExpectedType(booleanType)) + if (KotlinTypeChecker.DEFAULT.equalTypes(booleanType, checkedTypeInfo.type ?: type)) { val ifInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(expression, true, newContext) val elseInfo = components.dataFlowAnalyzer.extractDataFlowInfoFromCondition(expression, false, newContext) return ConditionalDataFlowInfo(ifInfo, elseInfo) diff --git a/compiler/testData/diagnostics/tests/controlStructures/kt657.kt b/compiler/testData/diagnostics/tests/controlStructures/kt657.kt index 64693408667..3ea9283f14b 100644 --- a/compiler/testData/diagnostics/tests/controlStructures/kt657.kt +++ b/compiler/testData/diagnostics/tests/controlStructures/kt657.kt @@ -7,10 +7,10 @@ fun foo() = when { cond1() -> 12 cond2() -> 2 - 4 -> 34 - Pair(1, 2) -> 3 + 4 -> 34 + Pair(1, 2) -> 3 in 1..10 -> 34 - 4 -> 38 + 4 -> 38 is Int -> 33 else -> 34 } diff --git a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/conditions.kt b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/conditions.kt index 4f322c6cd65..551d125f87d 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/conditions.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/conditions.kt @@ -22,15 +22,15 @@ fun test() { val platformJ = J.staticJ if (platformNN) {} - if (platformN) {} + if (platformN) {} if (platformJ) {} while (platformNN) {} - while (platformN) {} + while (platformN) {} while (platformJ) {} do {} while (platformNN) - do {} while (platformN) + do {} while (platformN) do {} while (platformJ) platformNN && false diff --git a/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt new file mode 100644 index 00000000000..9a0d88c99b4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt @@ -0,0 +1,30 @@ +// See also: KT-11998 +data class My(val x: Boolean?) + +fun doIt() {} + +fun foo(my: My) { + if (my.x != null) { + // my.x should be smart-cast + if (my.x) doIt() + when (my.x) { + true -> doIt() + } + when { + my.x -> doIt() + } + } +} + +fun bar(x: Boolean?) { + if (x != null) { + // x should be smart-cast + if (x) doIt() + when (x) { + true -> doIt() + } + when { + x -> doIt() + } + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.txt b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.txt new file mode 100644 index 00000000000..ee30f3d295d --- /dev/null +++ b/compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.txt @@ -0,0 +1,15 @@ +package + +public fun bar(/*0*/ x: kotlin.Boolean?): kotlin.Unit +public fun doIt(): kotlin.Unit +public fun foo(/*0*/ my: My): kotlin.Unit + +public final data class My { + public constructor My(/*0*/ x: kotlin.Boolean?) + public final val x: kotlin.Boolean? + public final operator /*synthesized*/ fun component1(): kotlin.Boolean? + public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Boolean? = ...): My + 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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 9c222887e78..86e83b17c58 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -16764,6 +16764,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("propertyAsCondition.kt") + public void testPropertyAsCondition() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/propertyAsCondition.kt"); + doTest(fileName); + } + @TestMetadata("propertyToNotNull.kt") public void testPropertyToNotNull() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/smartCasts/propertyToNotNull.kt"); diff --git a/idea/testData/intentions/branched/ifThenToDoubleBang/conditionNotBinaryExpr.kt b/idea/testData/intentions/branched/ifThenToDoubleBang/conditionNotBinaryExpr.kt index e3cf013787a..797718fce2a 100644 --- a/idea/testData/intentions/branched/ifThenToDoubleBang/conditionNotBinaryExpr.kt +++ b/idea/testData/intentions/branched/ifThenToDoubleBang/conditionNotBinaryExpr.kt @@ -1,7 +1,7 @@ // WITH_RUNTIME // IS_APPLICABLE: false // ERROR: Type mismatch: inferred type is Int but Boolean was expected -// ERROR: Condition must be of type Boolean, but is of type Int +// ERROR: Type mismatch: inferred type is Int but Boolean was expected // ERROR: Infix call corresponds to a dot-qualified call 'foo.times(10)' which is not allowed on a nullable receiver 'foo'. Use '?.'-qualified call instead fun String?.times(a: Int): Boolean = a == 0 diff --git a/idea/testData/intentions/branched/ifThenToElvis/conditionNotBinaryExpr.kt b/idea/testData/intentions/branched/ifThenToElvis/conditionNotBinaryExpr.kt index c999f15f79a..9ca51c3bf07 100644 --- a/idea/testData/intentions/branched/ifThenToElvis/conditionNotBinaryExpr.kt +++ b/idea/testData/intentions/branched/ifThenToElvis/conditionNotBinaryExpr.kt @@ -1,6 +1,6 @@ // IS_APPLICABLE: false // ERROR: Type mismatch: inferred type is Int but Boolean was expected -// ERROR: Condition must be of type Boolean, but is of type Int +// ERROR: Type mismatch: inferred type is Int but Boolean was expected // ERROR: Infix call corresponds to a dot-qualified call 'foo.times(10)' which is not allowed on a nullable receiver 'foo'. Use '?.'-qualified call instead fun main(args: Array) {