diff --git a/idea/src/jet/lang/Library.jet b/idea/src/jet/lang/Library.jet index 6ba209c0c90..cd799e98dfc 100644 --- a/idea/src/jet/lang/Library.jet +++ b/idea/src/jet/lang/Library.jet @@ -110,7 +110,6 @@ class Double : Number, Comparable { class Float : Number, Comparable { 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 { class Long : Number, Comparable { 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 { class Int : Number, Comparable { 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 { class Char : Number, Comparable { 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 { fun minus() : Int } -class Short : Number, Comparable { +class Short : Number, Comparable { 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 { fun minus() : Int } -class Byte : Number, Comparable { +class Byte : Number, Comparable { 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 diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java b/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java index 31a0eb682d1..16eae226a81 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetContainerNode.java @@ -10,4 +10,9 @@ public class JetContainerNode extends JetElement { public JetContainerNode(@NotNull ASTNode node) { super(node); } + + @Override // for visibility + protected T findChildByClass(Class aClass) { + return super.findChildByClass(aClass); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetDeclaration.java b/idea/src/org/jetbrains/jet/lang/psi/JetDeclaration.java index 474e52ad484..bc4af407c63 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetDeclaration.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetDeclaration.java @@ -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); } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetExpression.java index 1c7e621cc59..fd4aff0f2ea 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetExpression.java @@ -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); } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java b/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java index 4ff9de963af..b9924b94211 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java @@ -331,7 +331,7 @@ public class JetVisitor extends PsiElementVisitor { } public void visitNamedDeclaration(JetNamedDeclaration declaration) { - visitJetElement(declaration); + visitDeclaration(declaration); } public void visitNullableType(JetNullableType nullableType) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java index 12a920b283a..e0e62888281 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/TopDownAnalyzer.java @@ -97,7 +97,7 @@ public class TopDownAnalyzer { @Override public void visitDeclaration(JetDeclaration dcl) { - throw new UnsupportedOperationException(); // TODO + // Other declarations do not declare visible types } }); } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index e3026027335..d83c9628b67 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -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 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 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 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 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()); + } } } diff --git a/idea/testData/resolve/Basic.jet b/idea/testData/resolve/Basic.jet index 5f8989de974..b34da0fa42c 100644 --- a/idea/testData/resolve/Basic.jet +++ b/idea/testData/resolve/Basic.jet @@ -30,5 +30,8 @@ fun test() : Unit { } for (~l~l : Int in 1..2) { `l`l`:std::Int` + while (true) { + `l`l + } } }