diff --git a/.idea/runConfigurations/All_Tests.xml b/.idea/runConfigurations/All_Tests.xml index 80abd8cce40..fe9f201fd2d 100644 --- a/.idea/runConfigurations/All_Tests.xml +++ b/.idea/runConfigurations/All_Tests.xml @@ -16,6 +16,7 @@ + diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java index 63beb6264aa..cece902df9e 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -287,7 +287,11 @@ public class JetTypeChecker { } public boolean isConvertibleTo(@NotNull JetType actual, @NotNull JetType expected) { - if (isSubtypeOf(actual, expected)) return true; + return isSubtypeOf(actual, expected) || + isConvertibleBySpecialConversion(actual, expected); + } + + public boolean isConvertibleBySpecialConversion(@NotNull JetType actual, @NotNull JetType expected) { if (expected.getConstructor().equals(JetStandardClasses.getTuple(0).getTypeConstructor())) { return true; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 1d51ae9f245..9b9fa6166be 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -289,13 +289,22 @@ public class JetTypeInferrer { for (Map.Entry entry : typeMap.entrySet()) { JetType actualType = entry.getValue(); JetElement element = entry.getKey(); - if (!semanticServices.getTypeChecker().isConvertibleTo(actualType, expectedReturnType)) { - if (element instanceof JetExpression) { - JetExpression expression = (JetExpression) element; - semanticServices.getErrorHandler().typeMismatch(expression, expectedReturnType, actualType); + JetTypeChecker typeChecker = semanticServices.getTypeChecker(); + if (!typeChecker.isSubtypeOf(actualType, expectedReturnType)) { + if (typeChecker.isConvertibleBySpecialConversion(actualType, expectedReturnType)) { + if (expectedReturnType.getConstructor().equals(JetStandardClasses.getUnitType().getConstructor()) && + element.getParent() instanceof JetReturnExpression) { + semanticServices.getErrorHandler().genericError(element.getNode(), "This function must return a value of type Unit"); + } } else { - semanticServices.getErrorHandler().genericError(element.getNode(), "This function must return a value of type " + expectedReturnType); + if (element instanceof JetExpression) { + JetExpression expression = (JetExpression) element; + semanticServices.getErrorHandler().typeMismatch(expression, expectedReturnType, actualType); + } + else { + semanticServices.getErrorHandler().genericError(element.getNode(), "This function must return a value of type " + expectedReturnType); + } } } } @@ -689,11 +698,19 @@ public class JetTypeInferrer { // TODO : change types according to is and null checks JetExpression elseBranch = expression.getElse(); JetExpression thenBranch = expression.getThen(); - JetType thenType = null; - if (thenBranch != null) { - thenType = getType(scope, thenBranch, true); + + if (elseBranch == null) { + if (thenBranch != null) { + getType(scope, thenBranch, true); + result = JetStandardClasses.getUnitType(); + } } - if (elseBranch != null) { + else if (thenBranch == null) { + getType(scope, elseBranch, true); + result = JetStandardClasses.getUnitType(); + } + else { + JetType thenType = getType(scope, thenBranch, true); JetType elseType = getType(scope, elseBranch, true); if (thenType == null) { result = elseType; @@ -705,9 +722,6 @@ public class JetTypeInferrer { result = semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType)); } } - else { - result = JetStandardClasses.getUnitType(); - } } private void checkCondition(@NotNull JetScope scope, @Nullable JetExpression condition) { diff --git a/idea/testData/cfg/Nonlocals.instructions b/idea/testData/cfg/Nonlocals.instructions index 85384dfecb1..56c7b0564ea 100644 --- a/idea/testData/cfg/Nonlocals.instructions +++ b/idea/testData/cfg/Nonlocals.instructions @@ -36,7 +36,7 @@ l5: ===================== == nonlocals1 == -fun nonlocals1(a : Boolean, b : Boolean) : Unit { +fun nonlocals1(a : Boolean, b : Boolean) : Any? { if (a) return 1 1 diff --git a/idea/testData/cfg/Nonlocals.jet b/idea/testData/cfg/Nonlocals.jet index ea03bba2a3c..ea9b7a2b275 100644 --- a/idea/testData/cfg/Nonlocals.jet +++ b/idea/testData/cfg/Nonlocals.jet @@ -1,4 +1,4 @@ -fun nonlocals1(a : Boolean, b : Boolean) : Unit { +fun nonlocals1(a : Boolean, b : Boolean) : Any? { if (a) return 1 1 diff --git a/idea/testData/checker/FunctionReturnTypes.jet b/idea/testData/checker/FunctionReturnTypes.jet index 5aa66116cfe..fddd7b9b307 100644 --- a/idea/testData/checker/FunctionReturnTypes.jet +++ b/idea/testData/checker/FunctionReturnTypes.jet @@ -3,6 +3,8 @@ fun unitEmptyInfer() {} fun unitEmpty() : Unit {} fun unitEmptyReturn() : Unit {return} +fun unitIntReturn() : Unit {return 1} +fun unitUnitReturn() : Unit {return ()} fun unitShort() : Unit = () fun unitShortConv() : Unit = 1 fun unitShortNull() : Unit = null diff --git a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java index c7c6a6f54a0..78a674ae48e 100644 --- a/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java +++ b/idea/tests/org/jetbrains/jet/types/JetTypeCheckerTest.java @@ -101,6 +101,9 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { assertType("if (true) null else null", "Nothing?"); assertType("if (true) 1 else '1'", "Any"); + + assertType("if (true) else '1'", "Unit"); + assertType("if (true) else a = 0", "Unit"); } public void testWhen() throws Exception {