Resolve for 'for' and 'while', 'do..while' pending

This commit is contained in:
Andrey Breslav
2011-03-17 14:43:00 +03:00
parent fd7abde114
commit 1c36c9be16
9 changed files with 206 additions and 71 deletions
+11 -11
View File
@@ -159,8 +159,8 @@ class Float : Number, Comparable<Float> {
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : Range<Float>
fun rangeTo(other : Int) : Range<Float>
fun rangeTo(other : Long) : Range<Double>
fun rangeTo(other : Int) : Range<Double>
fun rangeTo(other : Short) : Range<Float>
fun rangeTo(other : Byte) : Range<Float>
fun rangeTo(other : Char) : Range<Float>
@@ -221,7 +221,7 @@ class Long : Number, Comparable<Long> {
fun mod(other : Char) : Long
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Float) : Range<Double>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Long>
fun rangeTo(other : Short) : IntRange<Long>
@@ -284,7 +284,7 @@ class Int : Number, Comparable<Int> {
fun mod(other : Char) : Int
fun rangeTo(other : Double) : Range<Double>
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Float) : Range<Double>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Int>
@@ -350,9 +350,9 @@ class Char : Number, Comparable<Char> {
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Int>
fun rangeTo(other : Byte) : IntRange<Int>
fun rangeTo(other : Char) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Short>
fun rangeTo(other : Byte) : IntRange<Byte>
fun rangeTo(other : Char) : IntRange<Char>
fun inc() : Char
fun dec() : Char
@@ -413,8 +413,8 @@ class Short : Number, Comparable<Char> {
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Int>
fun rangeTo(other : Byte) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Short>
fun rangeTo(other : Byte) : IntRange<Short>
fun rangeTo(other : Char) : IntRange<Int>
fun inc() : Short
@@ -476,8 +476,8 @@ class Byte : Number, Comparable<Char> {
fun rangeTo(other : Float) : Range<Float>
fun rangeTo(other : Long) : IntRange<Long>
fun rangeTo(other : Int) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Int>
fun rangeTo(other : Byte) : IntRange<Int>
fun rangeTo(other : Short) : IntRange<Short>
fun rangeTo(other : Byte) : IntRange<Byte>
fun rangeTo(other : Char) : IntRange<Int>
fun inc() : Byte
@@ -7,7 +7,10 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
@@ -57,6 +60,7 @@ public class ClassDescriptorResolver {
WritableScope parameterScope = descriptor.getUnsubstitutedMemberScope();
// This call has side-effects on the parameterScope (fills it in)
List<TypeParameterDescriptor> typeParameters
= resolveTypeParameters(descriptor, parameterScope, classElement.getTypeParameters());
@@ -86,6 +90,7 @@ public class ClassDescriptorResolver {
// TODO : importing may be a bad idea
for (JetType supertype : superclasses) {
assert supertype != null : classElement.getName();
parameterScope.importScope(supertype.getMemberScope());
}
@@ -224,7 +229,7 @@ public class ClassDescriptorResolver {
typeParameter.getVariance(),
typeParameter.getName(),
extendsBound == null
? Collections.<JetType>singleton(JetStandardClasses.getAnyType())
? Collections.<JetType>singleton(JetStandardClasses.getDefaultBound())
: Collections.singleton(typeResolver.resolveType(extensibleScope, extendsBound))
);
extensibleScope.addTypeParameterDescriptor(typeParameterDescriptor);
@@ -250,11 +255,23 @@ public class ClassDescriptorResolver {
@NotNull
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, @NotNull JetParameter parameter) {
JetTypeReference typeReference = parameter.getTypeReference();
JetType type;
if (typeReference != null) {
type = typeResolver.resolveType(scope, typeReference);
}
else {
type = ErrorType.createErrorType("Annotation is absent");
}
return resolvePropertyDescriptor(containingDeclaration, parameter, type);
}
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetParameter parameter, @NotNull JetType type) {
return new PropertyDescriptorImpl(
containingDeclaration,
AttributeResolver.INSTANCE.resolveAttributes(parameter.getModifierList()),
parameter.getName(),
typeResolver.resolveType(scope, parameter.getTypeReference()));
type);
}
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
@@ -37,6 +37,7 @@ public class MutableClassDescriptor extends MutableDeclarationDescriptor impleme
return new SubstitutingScope(unsubstitutedMemberScope, substitutionContext);
}
@NotNull
public WritableScope getUnsubstitutedMemberScope() {
return unsubstitutedMemberScope;
}
@@ -45,8 +45,8 @@ public class JetStandardClasses {
}
}, JetScope.EMPTY
);
private static final JetType NOTHING_TYPE = new JetTypeImpl(getNothing());
private static final JetType NOTHING_TYPE = new JetTypeImpl(getNothing());
private static final JetType NULLABLE_NOTHING_TYPE = new JetTypeImpl(
Collections.<Attribute>emptyList(),
getNothing().getTypeConstructor(),
@@ -65,8 +65,8 @@ public class JetStandardClasses {
Collections.<JetType>emptySet(),
JetScope.EMPTY
);
private static final JetType ANY_TYPE = new JetTypeImpl(ANY.getTypeConstructor(), JetScope.EMPTY);
private static final JetType ANY_TYPE = new JetTypeImpl(ANY.getTypeConstructor(), JetScope.EMPTY);
private static final JetType NULLABLE_ANY_TYPE = TypeUtils.makeNullable(ANY_TYPE);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -76,8 +76,8 @@ public class JetStandardClasses {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static final int TUPLE_COUNT = 22;
private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT];
private static final ClassDescriptor[] TUPLE = new ClassDescriptor[TUPLE_COUNT];
static {
for (int i = 0; i < TUPLE_COUNT; i++) {
List<TypeParameterDescriptor> parameters = new ArrayList<TypeParameterDescriptor>();
@@ -102,8 +102,8 @@ public class JetStandardClasses {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static final int FUNCTION_COUNT = 22;
private static final ClassDescriptor[] FUNCTION = new ClassDescriptor[FUNCTION_COUNT];
private static final ClassDescriptor[] FUNCTION = new ClassDescriptor[FUNCTION_COUNT];
private static final ClassDescriptor[] RECEIVER_FUNCTION = new ClassDescriptor[FUNCTION_COUNT];
static {
@@ -191,8 +191,15 @@ public class JetStandardClasses {
}
}
private static final JetType DEFAULT_BOUND = getNullableAnyType();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@NotNull
public static JetType getDefaultBound() {
return DEFAULT_BOUND;
}
@NotNull
public static ClassDescriptor getAny() {
return ANY;
@@ -49,6 +49,7 @@ public class JetStandardLibrary {
private final ClassDescriptor booleanClass;
private final ClassDescriptor stringClass;
private final ClassDescriptor arrayClass;
private final ClassDescriptor iterableClass;
private final JetType byteType;
private final JetType charType;
@@ -86,6 +87,7 @@ public class JetStandardLibrary {
this.booleanClass = libraryScope.getClass("Boolean");
this.stringClass = libraryScope.getClass("String");
this.arrayClass = libraryScope.getClass("Array");
this.iterableClass = libraryScope.getClass("Iterable");
this.byteType = new JetTypeImpl(getByte());
this.charType = new JetTypeImpl(getChar());
@@ -155,6 +157,11 @@ public class JetStandardLibrary {
return arrayClass;
}
@NotNull
public ClassDescriptor getIterable() {
return iterableClass;
}
@NotNull
public JetType getIntType() {
return intType;
@@ -217,4 +224,16 @@ public class JetStandardLibrary {
getArray().getMemberScope(types)
);
}
@NotNull
public JetType getIterableType(@NotNull JetType argument) {
List<TypeProjection> types = Collections.singletonList(new TypeProjection(Variance.INVARIANT, argument));
return new JetTypeImpl(
Collections.<Attribute>emptyList(),
getIterable().getTypeConstructor(),
false,
types,
getIterable().getMemberScope(types)
);
}
}
@@ -177,11 +177,14 @@ public class JetTypeChecker {
}
if (ins != null) {
Variance projectionKind = variance == Variance.IN_VARIANCE ? Variance.INVARIANT : Variance.IN_VARIANCE;
JetType intersection = TypeUtils.intersect(this, ins);
if (intersection == null) {
if (outs != null) {
return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(outs));
}
return new TypeProjection(Variance.OUT_VARIANCE, commonSupertype(parameterDescriptor.getUpperBounds()));
}
Variance projectionKind = variance == Variance.IN_VARIANCE ? Variance.INVARIANT : Variance.IN_VARIANCE;
return new TypeProjection(projectionKind, intersection);
} else if (outs != null) {
Variance projectionKind = variance == Variance.OUT_VARIANCE ? Variance.INVARIANT : Variance.OUT_VARIANCE;
@@ -165,7 +165,7 @@ public class JetTypeInferrer {
@Override
public void visitExpression(JetExpression expression) {
// <e> create a dummy domain for the type of e
throw new UnsupportedOperationException(); // TODO
throw new UnsupportedOperationException(expression.getText()); // TODO
}
@Override
@@ -436,55 +436,6 @@ public class JetTypeInferrer {
}
}
@Override
public void visitIfExpression(JetIfExpression expression) {
// TODO : check condition type
JetExpression condition = expression.getCondition();
if (condition != null) {
JetType conditionType = getType(scope, condition, false);
if (conditionType != null && !isBoolean(conditionType)) {
semanticServices.getErrorHandler().genericError(condition.getNode(), "Condition must be of type Boolean, but was of type " + conditionType);
}
}
// TODO : change types according to is and nullability checks
JetExpression elseBranch = expression.getElse();
if (elseBranch == null) {
// TODO : type-check the branch
result = JetStandardClasses.getUnitType();
} else {
JetType thenType = getType(scope, expression.getThen(), true);
JetType elseType = getType(scope, elseBranch, true);
result = semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType));
}
}
@Override
public void visitWhenExpression(JetWhenExpression expression) {
// TODO :change scope according to the bound value in the when header
List<JetType> expressions = new ArrayList<JetType>();
collectAllReturnTypes(expression, scope, expressions);
result = semanticServices.getTypeChecker().commonSupertype(expressions);
}
@Override
public void visitTryExpression(JetTryExpression expression) {
JetExpression tryBlock = expression.getTryBlock();
List<JetCatchClause> catchClauses = expression.getCatchClauses();
JetFinallySection finallyBlock = expression.getFinallyBlock();
List<JetType> types = new ArrayList<JetType>();
if (finallyBlock == null) {
for (JetCatchClause catchClause : catchClauses) {
// TODO: change scope here
types.add(getType(scope, catchClause.getCatchBody(), true));
}
} else {
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
}
types.add(getType(scope, tryBlock, true));
result = semanticServices.getTypeChecker().commonSupertype(types);
}
@Override
public void visitTupleExpression(JetTupleExpression expression) {
List<JetExpression> entries = expression.getEntries();
@@ -525,7 +476,125 @@ public class JetTypeInferrer {
}
@Override
public void visitLoopExpression(JetLoopExpression expression) {
public void visitWhenExpression(JetWhenExpression expression) {
// TODO :change scope according to the bound value in the when header
List<JetType> expressions = new ArrayList<JetType>();
collectAllReturnTypes(expression, scope, expressions);
result = semanticServices.getTypeChecker().commonSupertype(expressions);
}
@Override
public void visitTryExpression(JetTryExpression expression) {
JetExpression tryBlock = expression.getTryBlock();
List<JetCatchClause> catchClauses = expression.getCatchClauses();
JetFinallySection finallyBlock = expression.getFinallyBlock();
List<JetType> types = new ArrayList<JetType>();
if (finallyBlock == null) {
for (JetCatchClause catchClause : catchClauses) {
// TODO: change scope here
types.add(getType(scope, catchClause.getCatchBody(), true));
}
} else {
types.add(getType(scope, finallyBlock.getFinalExpression(), true));
}
types.add(getType(scope, tryBlock, true));
result = semanticServices.getTypeChecker().commonSupertype(types);
}
@Override
public void visitIfExpression(JetIfExpression expression) {
checkCondition(scope, expression.getCondition());
// TODO : change types according to is and nullability checks
JetExpression elseBranch = expression.getElse();
if (elseBranch == null) {
// TODO : type-check the branch
result = JetStandardClasses.getUnitType();
} else {
JetType thenType = getType(scope, expression.getThen(), true);
JetType elseType = getType(scope, elseBranch, true);
result = semanticServices.getTypeChecker().commonSupertype(Arrays.asList(thenType, elseType));
}
}
private void checkCondition(@NotNull JetScope scope, @Nullable JetExpression condition) {
if (condition != null) {
JetType conditionType = getType(scope, condition, false);
if (conditionType != null && !isBoolean(conditionType)) {
semanticServices.getErrorHandler().genericError(condition.getNode(), "Condition must be of type Boolean, but was of type " + conditionType);
}
}
}
@Override
public void visitWhileExpression(JetWhileExpression expression) {
checkCondition(scope, expression.getCondition());
JetExpression body = expression.getBody();
if (body != null) {
getType(scope, body, true);
}
result = JetStandardClasses.getUnitType();
}
@Override
public void visitDoWhileExpression(JetDoWhileExpression expression) {
JetExpression body = expression.getBody();
JetScope conditionScope = scope; // TODO
if (body != null) {
getType(scope, body, true);
}
checkCondition(conditionScope, expression.getCondition());
result = JetStandardClasses.getUnitType();
}
@Override
public void visitForExpression(JetForExpression expression) {
JetParameter loopParameter = expression.getLoopParameter();
JetExpression loopRange = expression.getLoopRange();
JetType loopRangeType = getType(scope, loopRange, false);
JetType expectedParameterType = null;
if (loopRangeType != null) {
if (!semanticServices.getTypeChecker().isSubtypeOf(loopRangeType, semanticServices.getStandardLibrary().getIterableType(JetStandardClasses.getNullableAnyType()))) {
semanticServices.getErrorHandler().genericError(loopRange.getNode(), "Expecting an Iterable, but found " + loopRangeType);
}
else {
TypeProjection typeProjection = loopRangeType.getArguments().get(0);
if (!typeProjection.getProjectionKind().allowsOutPosition()) {
expectedParameterType = JetStandardClasses.getDefaultBound();
}
else {
expectedParameterType = typeProjection.getType();
}
}
}
WritableScope loopScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
JetTypeReference typeReference = loopParameter.getTypeReference();
PropertyDescriptor propertyDescriptor;
if (typeReference != null) {
propertyDescriptor = semanticServices.getClassDescriptorResolver(trace).resolvePropertyDescriptor(scope.getContainingDeclaration(), scope, loopParameter);
JetType actualParameterType = propertyDescriptor.getType();
if (expectedParameterType != null &&
!semanticServices.getTypeChecker().isSubtypeOf(expectedParameterType, actualParameterType)) {
semanticServices.getErrorHandler().genericError(typeReference.getNode(), "The loop iterates over values of type " + expectedParameterType + " but the parameter is declared to be " + actualParameterType);
}
}
else {
if (expectedParameterType == null) {
expectedParameterType = ErrorType.createErrorType("Error");
}
propertyDescriptor = semanticServices.getClassDescriptorResolver(trace).resolvePropertyDescriptor(scope.getContainingDeclaration(), loopParameter, expectedParameterType);
}
loopScope.addPropertyDescriptor(propertyDescriptor);
trace.recordDeclarationResolution(loopParameter, propertyDescriptor);
JetExpression body = expression.getBody();
if (body != null) {
getType(loopScope, body, true); // TODO
}
result = JetStandardClasses.getUnitType();
}
@@ -844,6 +913,9 @@ public class JetTypeInferrer {
private JetType getTypeForBinaryCall(JetScope scope, JetExpression left, JetSimpleNameExpression operationSign, @NotNull JetExpression right, String name, boolean reportUnresolved) {
JetType leftType = safeGetType(scope, left, false);
JetType rightType = safeGetType(scope, right, false);
if (ErrorType.isErrorType(leftType)) {
return null;
}
FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, name, leftType, Collections.singletonList(rightType), reportUnresolved);
if (functionDescriptor != null) {
return functionDescriptor.getUnsubstitutedReturnType();
+15
View File
@@ -17,3 +17,18 @@
val x : `C.B`B
}
fun test() : Unit {
for (~i~i in 1..2) {
`i`i`:std::Int`
}
for (val ~j~j in 1..2) {
`j`j`:std::Int`
}
for (val ~k~k : Int in 1..2) {
`k`k`:std::Int`
}
for (~l~l : Int in 1..2) {
`l`l`:std::Int`
}
}
@@ -141,7 +141,8 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertCommonSupertype("Derived_T<Int>", "DDerived_T<Int>", "Derived_T<Int>");
assertCommonSupertype("Derived_T<Int>", "DDerived_T<Int>", "DDerived1_T<Int>");
assertCommonSupertype("Base_T<out Any>", "Base_T<Int>", "Base_T<Boolean>");
assertCommonSupertype("Comparable<*>", "Comparable<Int>", "Comparable<Boolean>");
assertCommonSupertype("Base_T<out Comparable<*>>", "Base_T<Int>", "Base_T<Boolean>");
assertCommonSupertype("Base_T<in Int>", "Base_T<Int>", "Base_T<in Int>");
assertCommonSupertype("Base_T<in Int>", "Derived_T<Int>", "Base_T<in Int>");
assertCommonSupertype("Base_T<in Int>", "Derived_T<in Int>", "Base_T<Int>");