'do..while' and assignments
This commit is contained in:
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,5 +30,8 @@ fun test() : Unit {
|
||||
}
|
||||
for (~l~l : Int in 1..2) {
|
||||
`l`l`:std::Int`
|
||||
while (true) {
|
||||
`l`l
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user