'do..while' and assignments

This commit is contained in:
Andrey Breslav
2011-03-17 17:12:55 +03:00
parent 1c36c9be16
commit 36513aabb9
8 changed files with 182 additions and 89 deletions
+6 -11
View File
@@ -110,7 +110,6 @@ class Double : Number, Comparable<Double> {
class Float : Number, Comparable<Float> {
fun compareTo(other : Double) : Int
fun compareTo(other : Float) : Int
fun compareTo(other : Long) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Short) : Int
@@ -174,7 +173,6 @@ class Float : Number, Comparable<Float> {
class Long : Number, Comparable<Long> {
fun compareTo(other : Double) : Int
fun compareTo(other : Float) : Int
fun compareTo(other : Long) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Short) : Int
fun compareTo(other : Byte) : Int
@@ -237,7 +235,7 @@ class Long : Number, Comparable<Long> {
class Int : Number, Comparable<Int> {
fun compareTo(other : Double) : Int
fun compareTo(other : Float) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Long) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Short) : Int
fun compareTo(other : Byte) : Int
@@ -300,11 +298,10 @@ class Int : Number, Comparable<Int> {
class Char : Number, Comparable<Char> {
fun compareTo(other : Double) : Int
fun compareTo(other : Float) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Long) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Short) : Int
fun compareTo(other : Byte) : Int
fun compareTo(other : Char) : Int
fun plus(other : Double) : Double
fun plus(other : Float) : Float
@@ -360,12 +357,11 @@ class Char : Number, Comparable<Char> {
fun minus() : Int
}
class Short : Number, Comparable<Char> {
class Short : Number, Comparable<Short> {
fun compareTo(other : Double) : Int
fun compareTo(other : Float) : Int
fun compareTo(other : Long) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Short) : Int
fun compareTo(other : Byte) : Int
fun compareTo(other : Char) : Int
@@ -423,13 +419,12 @@ class Short : Number, Comparable<Char> {
fun minus() : Int
}
class Byte : Number, Comparable<Char> {
class Byte : Number, Comparable<Byte> {
fun compareTo(other : Double) : Int
fun compareTo(other : Float) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Long) : Int
fun compareTo(other : Int) : Int
fun compareTo(other : Short) : Int
fun compareTo(other : Byte) : Int
fun compareTo(other : Char) : Int
fun plus(other : Double) : Double
@@ -10,4 +10,9 @@ public class JetContainerNode extends JetElement {
public JetContainerNode(@NotNull ASTNode node) {
super(node);
}
@Override // for visibility
protected <T> T findChildByClass(Class<T> aClass) {
return super.findChildByClass(aClass);
}
}
@@ -9,7 +9,7 @@ import org.jetbrains.jet.lexer.JetToken;
/**
* @author max
*/
public abstract class JetDeclaration extends JetElement {
public abstract class JetDeclaration extends JetExpression {
public JetDeclaration(@NotNull ASTNode node) {
super(node);
}
@@ -1,8 +1,6 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeType;
@@ -19,11 +17,10 @@ public class JetExpression extends JetElement {
visitor.visitExpression(this);
}
protected JetExpression findExpressionUnder(JetNodeType type) {
PsiElement containerNode = findChildByType(type);
JetContainerNode containerNode = (JetContainerNode) findChildByType(type);
if (containerNode == null) return null;
return PsiTreeUtil.findChildOfType(containerNode, JetExpression.class);
return containerNode.findChildByClass(JetExpression.class);
}
}
@@ -331,7 +331,7 @@ public class JetVisitor extends PsiElementVisitor {
}
public void visitNamedDeclaration(JetNamedDeclaration declaration) {
visitJetElement(declaration);
visitDeclaration(declaration);
}
public void visitNullableType(JetNullableType nullableType) {
@@ -97,7 +97,7 @@ public class TopDownAnalyzer {
@Override
public void visitDeclaration(JetDeclaration dcl) {
throw new UnsupportedOperationException(); // TODO
// Other declarations do not declare visible types
}
});
}
@@ -231,31 +231,25 @@ public class JetTypeInferrer {
} else {
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
WritableScope scope = semanticServices.createWritableScope(outerScope, containingDescriptor);
for (JetElement statement : block) {
// TODO: consider other declarations
if (statement instanceof JetProperty) {
JetProperty property = (JetProperty) statement;
PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePropertyDescriptor(containingDescriptor, scope, property);
scope.addPropertyDescriptor(propertyDescriptor);
trace.recordDeclarationResolution(property, propertyDescriptor);
}
else if (statement instanceof JetExpression) {
getType(scope, (JetExpression) statement, true);
}
else {
throw new UnsupportedOperationException(statement.getClass().getCanonicalName()); // TODO
}
}
JetElement lastElement = block.get(block.size() - 1);
if (lastElement instanceof JetExpression) {
JetExpression expression = (JetExpression) lastElement;
return getType(scope, expression, true);
}
// TODO: functions, classes, etc.
throw new IllegalArgumentException("Last item in the block must be an expression, but was " + lastElement.getClass().getCanonicalName());
return getBlockReturnedTypeWithWritableScope(scope, block);
}
}
private JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block) {
assert !block.isEmpty();
TypeInferrerVisitorWithWritableScope blockLevelVisitor = new TypeInferrerVisitorWithWritableScope(scope, true);
JetType result = null;
for (JetElement statement : block) {
statement.accept(blockLevelVisitor);
result = blockLevelVisitor.getResult();
if (result != null) {
trace.recordExpressionType((JetExpression) statement, result);
}
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
}
return result;
}
private void collectAllReturnTypes(JetWhenExpression whenExpression, JetScope scope, List<JetType> result) {
for (JetWhenEntry entry : whenExpression.getEntries()) {
JetWhenExpression subWhen = entry.getSubWhen();
@@ -272,7 +266,7 @@ public class JetTypeInferrer {
private class TypeInferrerVisitor extends JetVisitor {
private final JetScope scope;
private JetType result;
protected JetType result;
private final boolean preferBlock;
public TypeInferrerVisitor(JetScope scope, boolean preferBlock) {
@@ -540,9 +534,21 @@ public class JetTypeInferrer {
@Override
public void visitDoWhileExpression(JetDoWhileExpression expression) {
JetExpression body = expression.getBody();
JetScope conditionScope = scope; // TODO
if (body != null) {
getType(scope, body, true);
JetScope conditionScope = scope;
if (body instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression function = (JetFunctionLiteralExpression) body;
if (!function.hasParameterSpecification()) {
WritableScope writableScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
conditionScope = writableScope;
getBlockReturnedTypeWithWritableScope(writableScope, function.getBody());
} else {
getType(scope, body, true);
}
}
else if (body != null) {
WritableScope writableScope = semanticServices.createWritableScope(scope, scope.getContainingDeclaration());
conditionScope = writableScope;
getBlockReturnedTypeWithWritableScope(writableScope, Collections.singletonList(body));
}
checkCondition(conditionScope, expression.getCondition());
result = JetStandardClasses.getUnitType();
@@ -762,16 +768,10 @@ public class JetTypeInferrer {
result = getTypeForBinaryCall(expression, binaryOperationNames.get(operationType), scope, true);
}
else if (operationType == JetTokens.EQ) {
JetExpression deparenthesized = deparenthesize(left);
if (deparenthesized instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized;
resolveArrayAccessToLValue(arrayAccessExpression, expression.getRight(), expression.getOperationReference());
}
else {
getType(scope, expression.getRight(), false);
//throw new UnsupportedOperationException();
}
result = null; // TODO : This is not an expression, in fact!
visitAssignment(expression);
}
else if (assignmentOperationNames.containsKey(operationType)) {
visitAssignmentOperation(expression);
}
else if (comparisonOperations.contains(operationType)) {
JetType compareToReturnType = getTypeForBinaryCall(expression, "compareTo", scope, true);
@@ -786,16 +786,6 @@ public class JetTypeInferrer {
}
}
}
else if (assignmentOperationNames.containsKey(operationType)) {
String name = assignmentOperationNames.get(operationType);
JetType assignmentOperationType = getTypeForBinaryCall(expression, name, scope, false);
if (assignmentOperationType == null) {
String counterpartName = binaryOperationNames.get(assignmentOperationCounterparts.get(operationType));
getTypeForBinaryCall(expression, counterpartName, scope, true);
}
result = null; // TODO : not an expression
}
else if (equalsOperations.contains(operationType)) {
String name = "equals";
JetType equalsType = getTypeForBinaryCall(expression, name, scope, true);
@@ -845,6 +835,18 @@ public class JetTypeInferrer {
}
}
protected void visitAssignmentOperation(JetBinaryExpression expression) {
assignmentIsNotAnExpressionError(expression);
}
protected void visitAssignment(JetBinaryExpression expression) {
assignmentIsNotAnExpressionError(expression);
}
private void assignmentIsNotAnExpressionError(JetBinaryExpression expression) {
semanticServices.getErrorHandler().genericError(expression.getNode(), "Assignments are not expressions, and only expressions are allowed in this context");
}
private JetType assureBooleanResult(JetSimpleNameExpression operationSign, String name, JetType resultType) {
if (resultType != null) {
// TODO : Relax?
@@ -877,30 +879,7 @@ public class JetTypeInferrer {
}
}
private void resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign) {
List<JetType> argumentTypes = getTypes(scope, arrayAccessExpression.getIndexExpressions());
if (argumentTypes == null) return;
JetType rhsType = getType(scope, rightHandSide, false);
if (rhsType == null) return;
argumentTypes.add(rhsType);
JetType receiverType = getType(scope, arrayAccessExpression.getArrayExpression(), false);
if (receiverType == null) return;
// TODO : nasty hack: effort is duplicated
lookupFunction(scope, arrayAccessExpression, "set", receiverType, argumentTypes, true);
FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, "set", receiverType, argumentTypes, true);
if (functionDescriptor != null) {
result = functionDescriptor.getUnsubstitutedReturnType();
}
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem + " " + elem.getClass().getCanonicalName());
}
private JetType getTypeForBinaryCall(JetBinaryExpression expression, @NotNull String name, JetScope scope, boolean reportUnresolved) {
protected JetType getTypeForBinaryCall(JetBinaryExpression expression, @NotNull String name, JetScope scope, boolean reportUnresolved) {
JetExpression left = expression.getLeft();
JetExpression right = expression.getRight();
if (right == null) {
@@ -922,5 +901,119 @@ public class JetTypeInferrer {
}
return null;
}
@Override
public void visitDeclaration(JetDeclaration dcl) {
semanticServices.getErrorHandler().genericError(dcl.getNode(), "Declarations are not allowed in this position");
}
@Override
public void visitJetElement(JetElement elem) {
semanticServices.getErrorHandler().genericError(elem.getNode(), "Unsupported element: " + elem + " " + elem.getClass().getCanonicalName());
}
}
private class TypeInferrerVisitorWithWritableScope extends TypeInferrerVisitor {
private final WritableScope scope;
public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope, boolean preferBlock) {
super(scope, preferBlock);
this.scope = scope;
}
public void resetResult() {
this.result = null;
}
@Override
public void visitProperty(JetProperty property) {
PropertyDescriptor propertyDescriptor = classDescriptorResolver.resolvePropertyDescriptor(scope.getContainingDeclaration(), scope, property);
scope.addPropertyDescriptor(propertyDescriptor);
trace.recordDeclarationResolution(property, propertyDescriptor);
}
@Override
public void visitFunction(JetFunction function) {
super.visitFunction(function); // TODO
}
@Override
public void visitClass(JetClass klass) {
super.visitClass(klass); // TODO
}
@Override
public void visitExtension(JetExtension extension) {
super.visitExtension(extension); // TODO
}
@Override
public void visitTypedef(JetTypedef typedef) {
super.visitTypedef(typedef); // TODO
}
@Override
public void visitDeclaration(JetDeclaration dcl) {
visitJetElement(dcl);
}
@Override
protected void visitAssignmentOperation(JetBinaryExpression expression) {
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
String name = assignmentOperationNames.get(operationType);
JetType assignmentOperationType = getTypeForBinaryCall(expression, name, scope, false);
if (assignmentOperationType == null) {
String counterpartName = binaryOperationNames.get(assignmentOperationCounterparts.get(operationType));
getTypeForBinaryCall(expression, counterpartName, scope, true);
}
result = null; // not an expression
}
@Override
protected void visitAssignment(JetBinaryExpression expression) {
JetExpression left = expression.getLeft();
JetExpression deparenthesized = deparenthesize(left);
JetExpression right = expression.getRight();
if (deparenthesized instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized;
resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference());
}
else {
JetType leftType = getType(scope, left, false);
if (right != null) {
JetType rightType = getType(scope, right, false);
if (rightType != null &&
leftType != null &&
!semanticServices.getTypeChecker().isConvertibleTo(rightType, leftType)) {
semanticServices.getErrorHandler().typeMismatch(right, leftType, rightType);
}
}
}
result = null; // This is not an expression
}
private void resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign) {
List<JetType> argumentTypes = getTypes(scope, arrayAccessExpression.getIndexExpressions());
if (argumentTypes == null) return;
JetType rhsType = getType(scope, rightHandSide, false);
if (rhsType == null) return;
argumentTypes.add(rhsType);
JetType receiverType = getType(scope, arrayAccessExpression.getArrayExpression(), false);
if (receiverType == null) return;
// TODO : nasty hack: effort is duplicated
lookupFunction(scope, arrayAccessExpression, "set", receiverType, argumentTypes, true);
FunctionDescriptor functionDescriptor = lookupFunction(scope, operationSign, "set", receiverType, argumentTypes, true);
if (functionDescriptor != null) {
result = functionDescriptor.getUnsubstitutedReturnType();
}
}
@Override
public void visitJetElement(JetElement elem) {
semanticServices.getErrorHandler().genericError(elem.getNode(), "Unsupported element in a block: " + elem + " " + elem.getClass().getCanonicalName());
}
}
}
+3
View File
@@ -30,5 +30,8 @@ fun test() : Unit {
}
for (~l~l : Int in 1..2) {
`l`l`:std::Int`
while (true) {
`l`l
}
}
}