Types for this and loops

This commit is contained in:
Andrey Breslav
2011-02-03 18:01:45 +03:00
parent 5e93b1bcf7
commit 87ba042005
11 changed files with 110 additions and 36 deletions
@@ -8,7 +8,7 @@ import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
*/
public class JetDoWhileExpression extends JetExpression {
public class JetDoWhileExpression extends JetLoopExpression {
public JetDoWhileExpression(@NotNull ASTNode node) {
super(node);
}
@@ -23,8 +23,4 @@ public class JetDoWhileExpression extends JetExpression {
return findExpressionUnder(JetNodeTypes.CONDITION);
}
@Nullable
public JetExpression getBody() {
return findExpressionUnder(JetNodeTypes.BODY);
}
}
@@ -7,7 +7,7 @@ import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
*/
public class JetForExpression extends JetExpression {
public class JetForExpression extends JetLoopExpression {
public JetForExpression(@NotNull ASTNode node) {
super(node);
}
@@ -24,8 +24,4 @@ public class JetForExpression extends JetExpression {
public JetExpression getLoopRange() {
return findExpressionUnder(JetNodeTypes.LOOP_RANGE);
}
public JetExpression getBody() {
return findExpressionUnder(JetNodeTypes.BODY);
}
}
@@ -0,0 +1,20 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
/**
* @author abreslav
*/
public abstract class JetLoopExpression extends JetExpression {
public JetLoopExpression(@NotNull ASTNode node) {
super(node);
}
@Nullable
public JetExpression getBody() {
return findExpressionUnder(JetNodeTypes.BODY);
}
}
@@ -134,6 +134,10 @@ public class JetVisitor extends PsiElementVisitor {
visitJetElement(expression);
}
public void visitLoopExpression(JetLoopExpression loopExpression) {
visitExpression(loopExpression);
}
public void visitConstantExpression(JetConstantExpression expression) {
visitExpression(expression);
}
@@ -195,15 +199,15 @@ public class JetVisitor extends PsiElementVisitor {
}
public void visitForExpression(JetForExpression expression) {
visitExpression(expression);
visitLoopExpression(expression);
}
public void visitWhileExpression(JetWhileExpression expression) {
visitExpression(expression);
visitLoopExpression(expression);
}
public void visitDoWhileExpression(JetDoWhileExpression expression) {
visitExpression(expression);
visitLoopExpression(expression);
}
public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) {
@@ -8,7 +8,7 @@ import org.jetbrains.jet.JetNodeTypes;
/**
* @author max
*/
public class JetWhileExpression extends JetExpression {
public class JetWhileExpression extends JetLoopExpression {
public JetWhileExpression(@NotNull ASTNode node) {
super(node);
}
@@ -22,9 +22,4 @@ public class JetWhileExpression extends JetExpression {
public JetExpression getCondition() {
return findExpressionUnder(JetNodeTypes.CONDITION);
}
@Nullable
public JetExpression getBody() {
return findExpressionUnder(JetNodeTypes.BODY);
}
}
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.modules.MemberDomain;
import org.jetbrains.jet.lang.modules.NamespaceDomain;
@@ -14,4 +15,6 @@ public interface JetScope extends NamespaceDomain, MemberDomain {
@Nullable
TypeParameterDescriptor getTypeParameterDescriptor(String name);
@NotNull
Type getThisType();
}
@@ -6,13 +6,17 @@ import org.jetbrains.jet.lang.types.*;
* @author abreslav
*/
public class JetScopeAdapter implements JetScope {
private final JetScope scope;
public JetScopeAdapter(JetScope scope) {
this.scope = scope;
}
@Override
public Type getThisType() {
return scope.getThisType();
}
@Override
public TypeParameterDescriptor getTypeParameterDescriptor(String name) {
return scope.getTypeParameterDescriptor(name);
@@ -35,4 +35,9 @@ public abstract class JetScopeImpl implements JetScope {
public TypeParameterDescriptor getTypeParameterDescriptor(String name) {
return null;
}
@Override
public Type getThisType() {
return JetStandardClasses.getNothingType();
}
}
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.modules.MemberDomain;
import java.util.Collection;
@@ -25,6 +26,7 @@ public class ClassDescriptor extends MemberDescriptorImpl implements MemberDomai
Collections.<Type>singleton(JetStandardClasses.getAnyType()));
}
@NotNull
public TypeConstructor getTypeConstructor() {
return typeConstructor;
}
@@ -18,22 +18,17 @@ public class JetTypeChecker {
public static final JetTypeChecker INSTANCE = new JetTypeChecker();
/*
: try
: SimpleName
: "this" ("<" type ">")?
: "new" constructorInvocation
: objectLiteral
: "typeof" "(" expression ")"
: SimpleName
: declaration
: loop
: "typeof" "(" expression ")"
: functionLiteral
: declaration
: "namespace" // for the root namespace
*/
public Type getType(@NotNull final JetScope scope, @NotNull JetExpression expression) {
@@ -166,6 +161,28 @@ public class JetTypeChecker {
result[0] = JetStandardClasses.getTupleType(types);
}
@Override
public void visitThisExpression(JetThisExpression expression) {
// TODO : qualified this, e.g. Foo.this<Bar>
Type thisType = scope.getThisType();
JetTypeReference superTypeQualifier = expression.getSuperTypeQualifier();
if (superTypeQualifier != null) {
// This cast must be safe (assuming the PSI doesn't contain errors)
JetUserType typeElement = (JetUserType) superTypeQualifier.getTypeElement();
ClassDescriptor superclass = TypeResolver.INSTANCE.resolveClass(scope, typeElement);
Collection<? extends Type> supertypes = thisType.getConstructor().getSupertypes();
for (Type declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result[0] = substituteInType(getSubstitutionContext(thisType), declaredSupertype);
break;
}
}
assert result[0] != null;
} else {
result[0] = thisType;
}
}
@Override
public void visitBlockExpression(JetBlockExpression expression) {
// TODO : this is a stub, consider function literals
@@ -177,6 +194,11 @@ public class JetTypeChecker {
}
}
@Override
public void visitLoopExpression(JetLoopExpression expression) {
result[0] = JetStandardClasses.getUnitType();
}
@Override
public void visitJetElement(JetElement elem) {
throw new IllegalArgumentException("Unsupported element: " + elem);
@@ -4,10 +4,7 @@ import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.project.Project;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.JetScopeImpl;
import org.jetbrains.jet.lang.resolve.TypeResolver;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.parsing.JetParsingTest;
@@ -170,10 +167,10 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertSubtype("()", "()");
assertSubtype("(Boolean)", "(Boolean)");
assertSubtype("(Byte)", "(Byte)");
assertSubtype("(Byte)", "(Byte)");
assertSubtype("(Char)", "(Char)");
assertSubtype("(Short)", "(Short)");
assertSubtype("(Int)", "(Int)");
assertSubtype("(Int)", "(Int)");
assertSubtype("(Long)", "(Long)");
assertSubtype("(Float)", "(Float)");
assertSubtype("(Double)", "(Double)");
@@ -266,6 +263,17 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertSubtype("Nothing?", "Derived_T<*>?");
}
public void testThis() throws Exception {
assertType("Derived_T<Int>", "this", "Derived_T<Int>");
assertType("Derived_T<Int>", "this<Base_T>", "Base_T<Int>");
}
public void testLoops() throws Exception {
assertType("while (1) {1}", "Unit");
assertType("do {1} while(1)", "Unit");
assertType("for (i in 1) {1}", "Unit");
}
public void testImplicitConversions() throws Exception {
assertConvertibleTo("1", JetStandardClasses.getByteType());
}
@@ -318,16 +326,35 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertTrue(type + " != " + expectedType, JetTypeChecker.INSTANCE.equalTypes(type, expectedType));
}
private void assertType(String contextType, String expression, String expectedType) {
final Type thisType = makeType(contextType);
JetScope scope = new JetScopeAdapter(ClassDefinitions.BASIC_SCOPE) {
@Override
public Type getThisType() {
return thisType;
}
};
assertType(scope, expression, expectedType);
}
private static void assertType(String expression, String expectedTypeStr) {
assertType(ClassDefinitions.BASIC_SCOPE, expression, expectedTypeStr);
}
private static void assertType(JetScope scope, String expression, String expectedTypeStr) {
Project project = getProject();
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
Type type = JetTypeChecker.INSTANCE.getType(ClassDefinitions.BASIC_SCOPE, jetExpression);
Type type = JetTypeChecker.INSTANCE.getType(scope, jetExpression);
Type expectedType = makeType(expectedTypeStr);
assertTrue(type + " != " + expectedType, JetTypeChecker.INSTANCE.equalTypes(type, expectedType));
}
private static Type makeType(String typeStr) {
return TypeResolver.INSTANCE.resolveType(ClassDefinitions.BASIC_SCOPE, JetChangeUtil.createType(getProject(), typeStr));
return makeType(ClassDefinitions.BASIC_SCOPE, typeStr);
}
private static Type makeType(JetScope scope, String typeStr) {
return TypeResolver.INSTANCE.resolveType(scope, JetChangeUtil.createType(getProject(), typeStr));
}
private static class ClassDefinitions {