Common supertypes found correctly for simple cases
This commit is contained in:
@@ -207,6 +207,10 @@ public class JetStandardClasses {
|
||||
return NULLABLE_NOTHING_TYPE;
|
||||
}
|
||||
|
||||
public static boolean isNothing(Type type) {
|
||||
return type.getConstructor() == NOTHING_CLASS.getTypeConstructor();
|
||||
}
|
||||
|
||||
public static Type getTupleType(List<Attribute> attributes, List<Type> arguments) {
|
||||
if (attributes.isEmpty() && arguments.isEmpty()) {
|
||||
return getUnitType();
|
||||
|
||||
@@ -6,10 +6,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.JetNodeTypes;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author abreslav
|
||||
@@ -18,18 +15,24 @@ public class JetTypeChecker {
|
||||
public static final JetTypeChecker INSTANCE = new JetTypeChecker();
|
||||
|
||||
/*
|
||||
: jump
|
||||
: if
|
||||
: when
|
||||
: try
|
||||
: functionLiteral
|
||||
|
||||
: SimpleName
|
||||
: "this" ("<" type ">")?
|
||||
: "typeof" "(" expression ")"
|
||||
|
||||
: "new" constructorInvocation
|
||||
|
||||
: objectLiteral
|
||||
|
||||
: "typeof" "(" expression ")"
|
||||
|
||||
: declaration
|
||||
: loop
|
||||
: SimpleName
|
||||
|
||||
: functionLiteral
|
||||
|
||||
: "namespace" // for the root namespace
|
||||
*/
|
||||
public Type getType(JetExpression expression) {
|
||||
@@ -94,6 +97,21 @@ public class JetTypeChecker {
|
||||
throw new UnsupportedOperationException("Return some reflection interface"); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIfExpression(JetIfExpression expression) {
|
||||
// TODO : check condition type
|
||||
// TODO : change types according to is and nullability according to null comparisons
|
||||
JetExpression elseBranch = expression.getElse();
|
||||
if (elseBranch == null) {
|
||||
// TODO : type-check the branch
|
||||
result[0] = JetStandardClasses.getUnitType();
|
||||
} else {
|
||||
Type thenType = getType(expression.getThen());
|
||||
Type elseType = getType(elseBranch);
|
||||
result[0] = commonSupertype(thenType, elseType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTupleExpression(JetTupleExpression expression) {
|
||||
List<JetExpression> entries = expression.getEntries();
|
||||
@@ -113,6 +131,49 @@ public class JetTypeChecker {
|
||||
return result[0];
|
||||
}
|
||||
|
||||
private Type commonSupertype(Type thenType, Type elseType) {
|
||||
if (JetStandardClasses.isNothing(thenType)) {
|
||||
return elseType;
|
||||
}
|
||||
if (JetStandardClasses.isNothing(elseType)) {
|
||||
return thenType;
|
||||
}
|
||||
|
||||
List<Type> thenOrder = new LinkedList<Type>(); // adding to the beginning
|
||||
Map<TypeConstructor, Type> visited = new HashMap<TypeConstructor, Type>();
|
||||
topologicallySort(thenType, visited, thenOrder, null);
|
||||
|
||||
List<Type> elseOrder = new LinkedList<Type>(); // adding to the beginning
|
||||
topologicallySort(elseType, new HashMap<TypeConstructor, Type>(), elseOrder, visited);
|
||||
|
||||
assert !elseOrder.isEmpty() : "No common supertype";
|
||||
// TODO: support multiple common supertypes
|
||||
|
||||
return elseOrder.get(0);
|
||||
}
|
||||
|
||||
private void topologicallySort(Type current, Map<TypeConstructor, Type> visited, List<Type> topologicalOrder, @Nullable Map<TypeConstructor, Type> filter) {
|
||||
Type visitedOccurrence = visited.put(current.getConstructor(), current);
|
||||
if (visitedOccurrence != null) {
|
||||
assert equalTypes(visitedOccurrence, current);
|
||||
return;
|
||||
}
|
||||
Map<TypeConstructor, TypeProjection> substitutionContext = getSubstitutionContext(current);
|
||||
for (Type supertype : current.getConstructor().getSupertypes()) {
|
||||
TypeConstructor supertypeConstructor = supertype.getConstructor();
|
||||
if (visited.containsKey(supertypeConstructor)) {
|
||||
assert equalTypes(visited.get(supertypeConstructor), supertype);
|
||||
continue;
|
||||
}
|
||||
Type substitutedSupertype = substitute(substitutionContext, supertype);
|
||||
topologicallySort(substitutedSupertype, visited, topologicalOrder, filter);
|
||||
}
|
||||
if (filter != null && filter.containsKey(current.getConstructor())) {
|
||||
assert equalTypes(filter.get(current.getConstructor()), current);
|
||||
topologicalOrder.add(0, current);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConvertibleTo(JetExpression expression, Type type) {
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
@@ -121,7 +182,7 @@ public class JetTypeChecker {
|
||||
if (!supertype.isNullable() && subtype.isNullable()) {
|
||||
return false;
|
||||
}
|
||||
if (subtype.getConstructor() == JetStandardClasses.getNothing().getTypeConstructor()) {
|
||||
if (JetStandardClasses.isNothing(subtype)) {
|
||||
return true;
|
||||
}
|
||||
@Nullable Type closestSupertype = findCorrespondingSupertype(subtype, supertype);
|
||||
@@ -143,13 +204,13 @@ public class JetTypeChecker {
|
||||
for (Type immediateSupertype : constructor.getSupertypes()) {
|
||||
Type correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype);
|
||||
if (correspondingSupertype != null) {
|
||||
return substituteForParameters(subtype, correspondingSupertype);
|
||||
return substitute(getSubstitutionContext(subtype), correspondingSupertype);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Type substituteForParameters(Type context, Type subject) {
|
||||
private Map<TypeConstructor, TypeProjection> getSubstitutionContext(Type context) {
|
||||
Map<TypeConstructor, TypeProjection> parameterValues = new HashMap<TypeConstructor, TypeProjection>();
|
||||
|
||||
List<TypeParameterDescriptor> parameters = context.getConstructor().getParameters();
|
||||
@@ -159,8 +220,7 @@ public class JetTypeChecker {
|
||||
TypeProjection value = contextArguments.get(i);
|
||||
parameterValues.put(parameter.getTypeConstructor(), value);
|
||||
}
|
||||
|
||||
return substitute(parameterValues, subject);
|
||||
return parameterValues;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -76,6 +76,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
|
||||
assertType("break \"foo\"", JetStandardClasses.getNothingType());
|
||||
}
|
||||
|
||||
public void testIf() throws Exception {
|
||||
assertType("if (true) 1", JetStandardClasses.getUnitType());
|
||||
assertType("if (true) 1 else 1", JetStandardClasses.getIntType());
|
||||
assertType("if (true) 1 else return", JetStandardClasses.getIntType());
|
||||
assertType("if (true) return else 1", JetStandardClasses.getIntType());
|
||||
assertType("if (true) return else return", JetStandardClasses.getNothingType());
|
||||
}
|
||||
|
||||
public void testBasicSubtyping() throws Exception {
|
||||
assertSubtype("Boolean", "Boolean");
|
||||
assertSubtype("Byte", "Byte");
|
||||
|
||||
Reference in New Issue
Block a user