From 5ad5a0e5e9b9391fed497078e943a5a52dd8861b Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 19 May 2011 23:34:27 +0400 Subject: [PATCH] Type checking for basic patterns --- .../jet/lang/types/JetTypeInferrer.java | 109 +++++++++++------- idea/testData/checker/When.jet | 25 +++- 2 files changed, 90 insertions(+), 44 deletions(-) diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 9969f249a80..24b54f28238 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -1019,49 +1019,7 @@ public class JetTypeInferrer { @Override public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) { - JetPattern pattern = condition.getPattern(); - if (pattern != null) { - pattern.accept(new JetVisitor() { - @Override - public void visitTypePattern(JetTypePattern typePattern) { - JetTypeReference typeReference = typePattern.getTypeReference(); - if (typeReference != null) { - JetType type = typeResolver.resolveType(scope, typeReference); - if (TypeUtils.intersect(semanticServices.getTypeChecker(), Sets.newHashSet(type, finalSubjectType)) == null) { - trace.getErrorHandler().genericError(typePattern.getNode(), "Incompatible types"); // TODO : message - } - } - } - - @Override - public void visitWildcardPattern(JetWildcardPattern pattern) { - // Nothing - } - - @Override - public void visitExpressionPattern(JetExpressionPattern pattern) { - getType(scope, pattern.getExpression(), false); // TODO : check type compatibility - trace.getErrorHandler().genericWarning(pattern.getNode(), "TODO : Types not checked"); - } - - @Override - public void visitTuplePattern(JetTuplePattern pattern) { - for (JetTuplePatternEntry entry : pattern.getEntries()) { - // TODO : is a name always allowed, ie for tuple patterns, not decomposer arg lists? - String nameLabel = entry.getNameLabel(); - JetPattern entryPattern = entry.getPattern(); - if (entryPattern != null) { - entryPattern.accept(this); // TODO : type checking - } - } - } - - @Override - public void visitJetElement(JetElement elem) { - trace.getErrorHandler().genericError(elem.getNode(), "Unsupported [JetTypeInferrer]"); - } - }); - } + checkPatternType(condition.getPattern(), finalSubjectType); } @Override @@ -1082,6 +1040,71 @@ public class JetTypeInferrer { } } + private void checkPatternType(@NotNull JetPattern pattern, @NotNull final JetType subjectType) { + pattern.accept(new JetVisitor() { + @Override + public void visitTypePattern(JetTypePattern typePattern) { + JetTypeReference typeReference = typePattern.getTypeReference(); + if (typeReference != null) { + JetType type = typeResolver.resolveType(scope, typeReference); + checkTypeCompatibility(type, subjectType, typePattern); + } + } + + @Override + public void visitWildcardPattern(JetWildcardPattern pattern) { + // Nothing + } + + @Override + public void visitExpressionPattern(JetExpressionPattern pattern) { + JetType type = getType(scope, pattern.getExpression(), false); + checkTypeCompatibility(type, subjectType, pattern); + } + + @Override + public void visitTuplePattern(JetTuplePattern pattern) { + List entries = pattern.getEntries(); + TypeConstructor typeConstructor = subjectType.getConstructor(); + if (!JetStandardClasses.getTuple(entries.size()).getTypeConstructor().equals(typeConstructor) + || typeConstructor.getParameters().size() != entries.size()) { + trace.getErrorHandler().genericError(pattern.getNode(), "Type mismatch: subject is of type " + subjectType + " but the pattern if of type Tuple" + entries.size()); // TODO : message + } + else { + for (int i = 0, entriesSize = entries.size(); i < entriesSize; i++) { + JetTuplePatternEntry entry = entries.get(i); + JetType type = subjectType.getArguments().get(i).getType(); + + // TODO : is a name always allowed, ie for tuple patterns, not decomposer arg lists? + ASTNode nameLabelNode = entry.getNameLabelNode(); + if (nameLabelNode != null) { + trace.getErrorHandler().genericError(nameLabelNode, "Unsupported [JetTypeInferrer]"); + } + + JetPattern entryPattern = entry.getPattern(); + if (entryPattern != null) { + checkPatternType(entryPattern, type); + } + } + } + } + + private void checkTypeCompatibility(@Nullable JetType type, @NotNull JetType subjectType, @NotNull JetElement reportErrorOn) { + if (type == null) { + return; + } + if (TypeUtils.intersect(semanticServices.getTypeChecker(), Sets.newHashSet(type, subjectType)) == null) { + trace.getErrorHandler().genericError(reportErrorOn.getNode(), "Incompatible types: " + type + " and " + subjectType); // TODO : message + } + } + + @Override + public void visitJetElement(JetElement elem) { + trace.getErrorHandler().genericError(elem.getNode(), "Unsupported [JetTypeInferrer]"); + } + }); + } + @Override public void visitTryExpression(JetTryExpression expression) { JetExpression tryBlock = expression.getTryBlock(); diff --git a/idea/testData/checker/When.jet b/idea/testData/checker/When.jet index 5aafb51023e..0ba241e365a 100644 --- a/idea/testData/checker/When.jet +++ b/idea/testData/checker/When.jet @@ -21,4 +21,27 @@ fun foo() { } } -val _type_test : Int = foo() // this is needed to ensure the inferred return type of foo() \ No newline at end of file +val _type_test : Int = foo() // this is needed to ensure the inferred return type of foo() + +fun test() { + val x = 1; + val s = ""; + + when (x) { + s => 1 + is "" => 1 + x => 1 + is 1 => 1 + is (1, 1) => 1 + } + + val z = (1, 1) + + when (z) { + is (*, *) => 1 + is (*, 1) => 1 + is (1, 1) => 1 + is (1, "1") => 1 + is (1, "1", *) => 1 + } +} \ No newline at end of file