Types for this and loops
This commit is contained in:
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user