Typechecker logic fixed for one-branch ifs and 'return x' for Unit-returning functions
This commit is contained in:
Generated
+1
@@ -16,6 +16,7 @@
|
||||
<option name="VM_PARAMETERS" value="" />
|
||||
<option name="PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$" />
|
||||
<option name="FORK_MODE" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<option name="TEST_SEARCH_SCOPE">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -289,13 +289,22 @@ public class JetTypeInferrer {
|
||||
for (Map.Entry<JetElement, JetType> 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) {
|
||||
|
||||
@@ -36,7 +36,7 @@ l5:
|
||||
<END>
|
||||
=====================
|
||||
== nonlocals1 ==
|
||||
fun nonlocals1(a : Boolean, b : Boolean) : Unit {
|
||||
fun nonlocals1(a : Boolean, b : Boolean) : Any? {
|
||||
if (a)
|
||||
return 1
|
||||
1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
fun nonlocals1(a : Boolean, b : Boolean) : Unit {
|
||||
fun nonlocals1(a : Boolean, b : Boolean) : Any? {
|
||||
if (a)
|
||||
return 1
|
||||
1
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
fun unitEmptyInfer() {}
|
||||
fun unitEmpty() : Unit {}
|
||||
fun unitEmptyReturn() : Unit {return}
|
||||
fun unitIntReturn() : Unit {return <error>1</error>}
|
||||
fun unitUnitReturn() : Unit {return ()}
|
||||
fun unitShort() : Unit = ()
|
||||
fun unitShortConv() : Unit = 1
|
||||
fun unitShortNull() : Unit = null
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user