From 6d9529e826ea3ed992884cbc9ea326c47bcf1331 Mon Sep 17 00:00:00 2001 From: Svetlana Isakova Date: Wed, 1 Aug 2012 17:02:31 +0400 Subject: [PATCH] KT-948 Make type inference work with sure()/!! !! part fixed --- .../BasicExpressionTypingVisitor.java | 73 +++++++++++++------ .../tests/inference/regressions/kt948.kt | 18 +++++ .../nullabilityAndAutoCasts/AssertNotNull.kt | 2 +- .../TypeMismatchOnUnaryOperations.kt | 2 +- 4 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/inference/regressions/kt948.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 116f97626c3..b4c5a409669 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -793,18 +793,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { JetSimpleNameExpression operationSign = expression.getOperationReference(); + IElementType operationType = operationSign.getReferencedNameElementType(); // If it's a labeled expression - if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) { - String referencedName = operationSign.getReferencedName(); - referencedName = referencedName == null ? " " : referencedName; - context.labelResolver.enterLabeledElement(new LabelName(referencedName.substring(1)), baseExpression); - // TODO : Some processing for the label? - JetTypeInfo typeInfo = facade.getTypeInfo(baseExpression, context, isStatement); - context.labelResolver.exitLabeledElement(baseExpression); - return DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo()); + if (JetTokens.LABELS.contains(operationType)) { + return visitLabeledExpression(expression, context, isStatement); } - IElementType operationType = operationSign.getReferencedNameElementType(); + // Special case for expr!! + if (operationType == JetTokens.EXCLEXCL) { + return visitExclExclExpression(expression, context); + } // Type check the base expression JetTypeInfo typeInfo = facade.getTypeInfo(baseExpression, context.replaceExpectedType(NO_EXPECTED_TYPE)); @@ -814,18 +812,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { } DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); - // Special case for expr!! - if (operationType == JetTokens.EXCLEXCL) { - if (isKnownToBeNotNull(baseExpression, context)) { - context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, type)); - } - else { - DataFlowValue value = DataFlowValueFactory.INSTANCE.createDataFlowValue(baseExpression, type, context.trace.getBindingContext()); - dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL); - } - return DataFlowUtils.checkType(TypeUtils.makeNotNullable(type), expression, context, dataFlowInfo); - } - // Conventions for unary operations Name name = OperatorConventions.UNARY_OPERATION_NAMES.get(operationType); if (name == null) { @@ -882,6 +868,51 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return DataFlowUtils.checkType(result, expression, context, dataFlowInfo); } + private JetTypeInfo visitExclExclExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context) { + JetExpression baseExpression = expression.getBaseExpression(); + assert baseExpression != null; + JetSimpleNameExpression operationSign = expression.getOperationReference(); + assert operationSign.getReferencedNameElementType() == JetTokens.EXCLEXCL; + + JetType expectedType; + if (context.expectedType != NO_EXPECTED_TYPE) { + expectedType = TypeUtils.makeNullable(context.expectedType); + } + else { + expectedType = NO_EXPECTED_TYPE; + } + JetTypeInfo typeInfo = facade.getTypeInfo(baseExpression, context.replaceExpectedType(expectedType)); + JetType type = typeInfo.getType(); + if (type == null) { + return typeInfo; + } + DataFlowInfo dataFlowInfo = typeInfo.getDataFlowInfo(); + if (isKnownToBeNotNull(baseExpression, context)) { + context.trace.report(UNNECESSARY_NOT_NULL_ASSERTION.on(operationSign, type)); + } + else { + DataFlowValue value = DataFlowValueFactory.INSTANCE.createDataFlowValue(baseExpression, type, context.trace.getBindingContext()); + dataFlowInfo = dataFlowInfo.disequate(value, DataFlowValue.NULL); + } + return JetTypeInfo.create(TypeUtils.makeNotNullable(type), dataFlowInfo); + } + + private JetTypeInfo visitLabeledExpression(@NotNull JetUnaryExpression expression, @NotNull ExpressionTypingContext context, + boolean isStatement) { + JetExpression baseExpression = expression.getBaseExpression(); + assert baseExpression != null; + JetSimpleNameExpression operationSign = expression.getOperationReference(); + assert JetTokens.LABELS.contains(operationSign.getReferencedNameElementType()); + + String referencedName = operationSign.getReferencedName(); + referencedName = referencedName == null ? " " : referencedName; + context.labelResolver.enterLabeledElement(new LabelName(referencedName.substring(1)), baseExpression); + // TODO : Some processing for the label? + JetTypeInfo typeInfo = facade.getTypeInfo(baseExpression, context, isStatement); + context.labelResolver.exitLabeledElement(baseExpression); + return DataFlowUtils.checkType(typeInfo.getType(), expression, context, typeInfo.getDataFlowInfo()); + } + private boolean isKnownToBeNotNull(JetExpression expression, ExpressionTypingContext context) { JetType type = context.trace.get(EXPRESSION_TYPE, expression); assert type != null : "This method is only supposed to be called when the type is not null"; diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt948.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt948.kt new file mode 100644 index 00000000000..a2ac18fb759 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt948.kt @@ -0,0 +1,18 @@ +package a + +import java.util.* + +fun emptyList() : List? = ArrayList() + +fun foo() { + // type arguments shouldn't be required + val l : List = emptyList()!! + val l1 = emptyList()!! + + emptyList()!! : List + emptyList() : List? + + doWithList(emptyList()!!) +} + +fun doWithList(list: List) = list \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/AssertNotNull.kt b/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/AssertNotNull.kt index 6da7a053503..13a3ab2e45c 100644 --- a/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/AssertNotNull.kt +++ b/compiler/testData/diagnostics/tests/nullabilityAndAutoCasts/AssertNotNull.kt @@ -30,6 +30,6 @@ fun main(args : Array) { } } - val f : String = a!! + val f : String = a!! a!! : String } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/regressions/TypeMismatchOnUnaryOperations.kt b/compiler/testData/diagnostics/tests/regressions/TypeMismatchOnUnaryOperations.kt index c1800e156d4..ad77063b27d 100644 --- a/compiler/testData/diagnostics/tests/regressions/TypeMismatchOnUnaryOperations.kt +++ b/compiler/testData/diagnostics/tests/regressions/TypeMismatchOnUnaryOperations.kt @@ -2,7 +2,7 @@ fun main(args : Array) { val a : Int? = null; var v = 1 val b : String = v; - val f : String = a!!; + val f : String = a!!; val g : String = v++; val g1 : String = ++v; val h : String = v--;