From c7292cee7b049d819950dc829e91b4fa5eb064e5 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Mon, 17 Jan 2011 23:06:00 +0300 Subject: [PATCH] Working on the type model --- .../jet/lang/annotations/JetPsiChecker.java | 50 ++++++++++- .../jetbrains/jet/lang/psi/JetChangeUtil.java | 12 ++- .../jetbrains/jet/lang/psi/JetProperty.java | 7 ++ .../jet/lang/psi/JetTupleExpression.java | 2 +- .../jet/lang/psi/JetTypeParameter.java | 1 + .../jetbrains/jet/lang/psi/JetVisitor.java | 18 ++-- .../org/jetbrains/jet/lang/psi/Variance.java | 10 --- .../jetbrains/jet/lang/types/Annotated.java | 10 +++ .../jet/lang/types/AnnotatedImpl.java | 19 +++++ .../jetbrains/jet/lang/types/Annotation.java | 7 ++ .../jet/lang/types/ClassDescriptor.java | 29 +++++++ .../jetbrains/jet/lang/types/ClassType.java | 33 ++++++++ .../jet/lang/types/JetStandardClasses.java | 65 +++++++++++++++ .../jet/lang/types/JetStandardTypes.java | 64 +++++++++++++++ .../jet/lang/types/JetTypeChecker.java | 65 +++++++++++++++ .../jet/lang/types/MemberDescriptor.java | 7 ++ .../jet/lang/types/MemberDescriptorImpl.java | 12 +++ .../jet/lang/types/NamedAnnotatedImpl.java | 20 +++++ .../jetbrains/jet/lang/types/NothingType.java | 41 ++++++++++ .../jet/lang/types/ParameterDescriptor.java | 26 ++++++ .../jetbrains/jet/lang/types/TupleType.java | 82 +++++++++++++++++++ .../org/jetbrains/jet/lang/types/Type.java | 14 ++++ .../jet/lang/types/TypeConstructor.java | 33 ++++++++ .../jetbrains/jet/lang/types/TypeImpl.java | 46 +++++++++++ .../lang/types/TypeParameterDescriptor.java | 38 +++++++++ .../jet/lang/types/TypeProjection.java | 27 ++++++ .../jet/lang/types/TypeVariable.java | 22 +++++ .../jetbrains/jet/lang/types/Variance.java | 21 +++++ .../jet/parsing/JetTypeCheckerTest.java | 82 +++++++++++++++++++ 29 files changed, 840 insertions(+), 23 deletions(-) delete mode 100644 idea/src/org/jetbrains/jet/lang/psi/Variance.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/Annotated.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/AnnotatedImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/Annotation.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/ClassType.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/JetStandardTypes.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/MemberDescriptor.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/MemberDescriptorImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/NamedAnnotatedImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/NothingType.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/ParameterDescriptor.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/TupleType.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/Type.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/TypeImpl.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/TypeProjection.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/TypeVariable.java create mode 100644 idea/src/org/jetbrains/jet/lang/types/Variance.java create mode 100644 idea/tests/org/jetbrains/jet/parsing/JetTypeCheckerTest.java diff --git a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java index e3b297ea53e..fdf3e9bf7b6 100644 --- a/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/lang/annotations/JetPsiChecker.java @@ -1,10 +1,13 @@ package org.jetbrains.jet.lang.annotations; import com.intellij.lang.annotation.AnnotationHolder; +import com.intellij.lang.annotation.AnnotationSession; import com.intellij.lang.annotation.Annotator; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.psi.JetProperty; +import org.jetbrains.jet.lang.psi.*; + +import java.util.List; /** * @author abreslav @@ -13,9 +16,48 @@ public class JetPsiChecker implements Annotator { @Override public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if (element instanceof JetProperty) { - JetProperty property = (JetProperty) element; - holder.createErrorAnnotation(property.getNameIdentifier(), "Specify either type or value"); + if (element instanceof JetFile) { +// JetProperty property = (JetProperty) element; +// holder.createErrorAnnotation(property.getNameIdentifier(), "Specify either type or value"); + JetFile file = (JetFile) element; + String path = file.getProject().getBaseDir().getPath(); + System.out.println("Path: " + path); + JetNamespace rootNamespace = file.getRootNamespace(); + List declarations = rootNamespace.getDeclarations(); + + for (JetDeclaration declaration : declarations) { + declaration.accept(new JetVisitor() { + @Override + public void visitClass(JetClass klass) { + print("class "); + print(klass.getName()); + println("{"); + for (JetDeclaration decl : klass.getDeclarations()) { + decl.accept(this); + } + print("}"); + } + + @Override + public void visitProperty(JetProperty property) { + JetTypeReference propertyTypeRef = property.getPropertyTypeRef(); + String name = property.getName(); + } + + @Override + public void visitFunction(JetFunction fun) { + super.visitFunction(fun); //To change body of overridden methods use File | Settings | File Templates. + } + }); + } } } + + private void print(Object o) { + System.out.print(o); + } + + private void println(Object o) { + System.out.println(o); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java b/idea/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java index bfdfb33e2d7..685a93c096e 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetChangeUtil.java @@ -13,13 +13,23 @@ import java.util.List; * @author max */ public class JetChangeUtil { + public static JetExpression createExpression(Project project, String text) { + JetProperty property = createProperty(project, "val x = " + text); + return property.getInitializer(); + } + @NotNull public static JetFile createFile(Project project, String text) { return (JetFile) PsiFileFactory.getInstance(project).createFileFromText("dummy.jet", JetFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true); } public static JetProperty createProperty(Project project, String name, String type) { - JetFile file = createFile(project, "val " + name + (type != null ? ":" + type : "")); + String text = "val " + name + (type != null ? ":" + type : ""); + return createProperty(project, text); + } + + private static JetProperty createProperty(Project project, String text) { + JetFile file = createFile(project, text); JetNamespace rootNamespace = file.getRootNamespace(); List dcls = rootNamespace.getDeclarations(); assert dcls.size() == 1; diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java b/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java index b934096b030..a224040c26b 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java @@ -1,7 +1,9 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -79,4 +81,9 @@ public class JetProperty extends JetNamedDeclaration { return null; } + + public JetExpression getInitializer() { + PsiElement eq = findChildByType(JetTokens.EQ); + return PsiTreeUtil.getNextSiblingOfType(eq, JetExpression.class); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTupleExpression.java b/idea/src/org/jetbrains/jet/lang/psi/JetTupleExpression.java index b4e43e51496..b707e3c7a42 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTupleExpression.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTupleExpression.java @@ -19,7 +19,7 @@ public class JetTupleExpression extends JetExpression { visitor.visitTupleExpression(this); } - public List getComponents() { + public List getEntries() { return PsiTreeUtil.getChildrenOfTypeAsList(this, JetExpression.class); } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameter.java b/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameter.java index 299e16ab61b..9cc8409ccb7 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameter.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetTypeParameter.java @@ -4,6 +4,7 @@ import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lang.types.Variance; import org.jetbrains.jet.lexer.JetTokens; /** diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java b/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java index 415423cb5c7..4e62060988c 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetVisitor.java @@ -19,7 +19,7 @@ public class JetVisitor extends PsiElementVisitor { } public void visitClass(JetClass klass) { - visitDeclaration(klass); + visitNamedDeclaration(klass); } public void visitClassObject(JetClassObject classObject) { @@ -31,19 +31,19 @@ public class JetVisitor extends PsiElementVisitor { } public void visitExtension(JetExtension extension) { - visitDeclaration(extension); + visitNamedDeclaration(extension); } public void visitFunction(JetFunction fun) { - visitDeclaration(fun); + visitNamedDeclaration(fun); } public void visitProperty(JetProperty property) { - visitDeclaration(property); + visitNamedDeclaration(property); } public void visitTypedef(JetTypedef typedef) { - visitDeclaration(typedef); + visitNamedDeclaration(typedef); } public void visitJetFile(JetFile file) { @@ -79,7 +79,7 @@ public class JetVisitor extends PsiElementVisitor { } public void visitTypeParameter(JetTypeParameter parameter) { - visitDeclaration(parameter); + visitNamedDeclaration(parameter); } public void visitEnumEntry(JetEnumEntry enumEntry) { @@ -91,7 +91,7 @@ public class JetVisitor extends PsiElementVisitor { } public void visitParameter(JetParameter parameter) { - visitDeclaration(parameter); + visitNamedDeclaration(parameter); } public void visitDelegationSpecifierList(JetDelegationSpecifierList list) { @@ -317,4 +317,8 @@ public class JetVisitor extends PsiElementVisitor { public void visitMatchBlock(JetMatchBlock block) { visitJetElement(block); } + + public void visitNamedDeclaration(JetNamedDeclaration declaration) { + visitJetElement(declaration); + } } diff --git a/idea/src/org/jetbrains/jet/lang/psi/Variance.java b/idea/src/org/jetbrains/jet/lang/psi/Variance.java deleted file mode 100644 index db46df2e33c..00000000000 --- a/idea/src/org/jetbrains/jet/lang/psi/Variance.java +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.jet.lang.psi; - -/** - * @author max - */ -public enum Variance { - INVARIANT, - IN_VARIANCE, - OUT_VARIANCE -} diff --git a/idea/src/org/jetbrains/jet/lang/types/Annotated.java b/idea/src/org/jetbrains/jet/lang/types/Annotated.java new file mode 100644 index 00000000000..5d7aef15d40 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/Annotated.java @@ -0,0 +1,10 @@ +package org.jetbrains.jet.lang.types; + +import java.util.List; + +/** + * @author abreslav + */ +public interface Annotated { + List getAnnotations(); +} diff --git a/idea/src/org/jetbrains/jet/lang/types/AnnotatedImpl.java b/idea/src/org/jetbrains/jet/lang/types/AnnotatedImpl.java new file mode 100644 index 00000000000..1527a1a9c23 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/AnnotatedImpl.java @@ -0,0 +1,19 @@ +package org.jetbrains.jet.lang.types; + +import java.util.List; + +/** + * @author abreslav + */ +public abstract class AnnotatedImpl implements Annotated { + private final List annotations; + + public AnnotatedImpl(List annotations) { + this.annotations = annotations; + } + + @Override + public List getAnnotations() { + return annotations; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/Annotation.java b/idea/src/org/jetbrains/jet/lang/types/Annotation.java new file mode 100644 index 00000000000..e233fa1a1ec --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/Annotation.java @@ -0,0 +1,7 @@ +package org.jetbrains.jet.lang.types; + +/** + * @author abreslav + */ +public interface Annotation { +} diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java new file mode 100644 index 00000000000..8d51a62cbbc --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/ClassDescriptor.java @@ -0,0 +1,29 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author abreslav + */ +public class ClassDescriptor extends MemberDescriptorImpl { + private final TypeConstructor typeConstructor; + + public ClassDescriptor( + List annotations, + String name, List typeParameters, Collection superclasses) { + super(annotations, name); + this.typeConstructor = new TypeConstructor(annotations, name, typeParameters, superclasses); + } + + public ClassDescriptor(String name) { + this(Collections.emptyList(), + name, Collections.emptyList(), + Collections.singleton(JetStandardTypes.getAny())); + } + + public TypeConstructor getTypeConstructor() { + return typeConstructor; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/ClassType.java b/idea/src/org/jetbrains/jet/lang/types/ClassType.java new file mode 100644 index 00000000000..60fd0fe8909 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/ClassType.java @@ -0,0 +1,33 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author abreslav + */ +public class ClassType extends TypeImpl { + private final ClassDescriptor classDescriptor; + + public ClassType(List annotations, ClassDescriptor classDescriptor, List arguments) { + super(annotations, classDescriptor.getTypeConstructor(), arguments); + assert classDescriptor.getTypeConstructor().getParameters().size() == arguments.size(); + + this.classDescriptor = classDescriptor; + } + + public ClassType(ClassDescriptor classDescriptor) { + this(Collections.emptyList(), classDescriptor, Collections.emptyList()); + assert classDescriptor.getTypeConstructor().getParameters().size() == 0; + } + + public ClassDescriptor getClassDescriptor() { + return classDescriptor; + } + + @Override + public Collection getMembers() { + throw new UnsupportedOperationException(); // TODO + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java new file mode 100644 index 00000000000..0ad53301705 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -0,0 +1,65 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collections; + +/** + * @author abreslav + */ +public class JetStandardClasses { + private static final ClassDescriptor ANY = new ClassDescriptor( + Collections.emptyList(), + "Any", + Collections.emptyList(), + Collections.emptySet() + ); + + private static final ClassDescriptor BYTE = new ClassDescriptor("Byte"); + private static final ClassDescriptor CHAR = new ClassDescriptor("Char"); + private static final ClassDescriptor SHORT = new ClassDescriptor("Short"); + private static final ClassDescriptor INT = new ClassDescriptor("Int"); + private static final ClassDescriptor LONG = new ClassDescriptor("Long"); + private static final ClassDescriptor FLOAT = new ClassDescriptor("Float"); + private static final ClassDescriptor DOUBLE = new ClassDescriptor("Double"); + private static final ClassDescriptor BOOLEAN = new ClassDescriptor("Boolean"); + private static final ClassDescriptor STRING = new ClassDescriptor("String"); + + public static ClassDescriptor getAny() { + return ANY; + } + + public static ClassDescriptor getByte() { + return BYTE; + } + + public static ClassDescriptor getChar() { + return CHAR; + } + + public static ClassDescriptor getShort() { + return SHORT; + } + + public static ClassDescriptor getInt() { + return INT; + } + + public static ClassDescriptor getLong() { + return LONG; + } + + public static ClassDescriptor getFloat() { + return FLOAT; + } + + public static ClassDescriptor getDouble() { + return DOUBLE; + } + + public static ClassDescriptor getBoolean() { + return BOOLEAN; + } + + public static ClassDescriptor getString() { + return STRING; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardTypes.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardTypes.java new file mode 100644 index 00000000000..4510a379bd1 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardTypes.java @@ -0,0 +1,64 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collections; + +/** + * @author abreslav + */ +public class JetStandardTypes { + private static final ClassType ANY_TYPE = new ClassType(JetStandardClasses.getAny()); + private static final ClassType BYTE = new ClassType(JetStandardClasses.getByte()); + private static final ClassType CHAR = new ClassType(JetStandardClasses.getChar()); + private static final ClassType SHORT = new ClassType(JetStandardClasses.getShort()); + private static final ClassType INT = new ClassType(JetStandardClasses.getInt()); + private static final ClassType LONG = new ClassType(JetStandardClasses.getLong()); + private static final ClassType FLOAT = new ClassType(JetStandardClasses.getFloat()); + private static final ClassType DOUBLE = new ClassType(JetStandardClasses.getDouble()); + private static final ClassType BOOLEAN = new ClassType(JetStandardClasses.getBoolean()); + private static final ClassType STRING = new ClassType(JetStandardClasses.getString()); + private static final TupleType UNIT = TupleType.UNIT; + + public static ClassType getInt() { + return INT; + } + + public static ClassType getLong() { + return LONG; + } + + public static ClassType getDouble() { + return DOUBLE; + } + + public static ClassType getFloat() { + return FLOAT; + } + + public static ClassType getChar() { + return CHAR; + } + + public static ClassType getBoolean() { + return BOOLEAN; + } + + public static ClassType getString() { + return STRING; + } + + public static ClassType getByte() { + return BYTE; + } + + public static ClassType getShort() { + return SHORT; + } + + public static TupleType getUnit() { + return UNIT; + } + + public static Type getAny() { + return ANY_TYPE; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java new file mode 100644 index 00000000000..051f63a2d0a --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeChecker.java @@ -0,0 +1,65 @@ +package org.jetbrains.jet.lang.types; + +import com.intellij.psi.tree.IElementType; +import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lang.psi.*; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author abreslav + */ +public class JetTypeChecker { + public Type getType(JetExpression expression) { + final Type[] result = new Type[1]; + expression.accept(new JetVisitor() { + @Override + public void visitConstantExpression(JetConstantExpression expression) { + IElementType elementType = expression.getNode().getElementType(); + if (elementType == JetNodeTypes.INTEGER_CONSTANT) { + result[0] = JetStandardTypes.getInt(); + } else if (elementType == JetNodeTypes.LONG_CONSTANT) { + result[0] = JetStandardTypes.getLong(); + } else if (elementType == JetNodeTypes.FLOAT_CONSTANT) { + String text = expression.getText(); + assert text.length() > 0; + char lastChar = text.charAt(text.length() - 1); + if (lastChar == 'f' || lastChar == 'F') { + result[0] = JetStandardTypes.getFloat(); + } else { + result[0] = JetStandardTypes.getDouble(); + } + } else if (elementType == JetNodeTypes.BOOLEAN_CONSTANT) { + result[0] = JetStandardTypes.getBoolean(); + } else if (elementType == JetNodeTypes.CHARACTER_CONSTANT) { + result[0] = JetStandardTypes.getChar(); + } else if (elementType == JetNodeTypes.STRING_CONSTANT) { + result[0] = JetStandardTypes.getString(); + } else { + throw new IllegalArgumentException("Unsupported constant: " + expression); + } + } + + @Override + public void visitTupleExpression(JetTupleExpression expression) { + List entries = expression.getEntries(); + List types = new ArrayList(); + for (JetExpression entry : entries) { + types.add(getType(entry)); + } + result[0] = TupleType.getTupleType(types); + } + + @Override + public void visitJetElement(JetElement elem) { + throw new IllegalArgumentException("Unsupported element: " + elem); + } + }); + return result[0]; + } + + public boolean isConvertibleTo(JetExpression expression, Type type) { + return false; //To change body of created methods use File | Settings | File Templates. + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/MemberDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/MemberDescriptor.java new file mode 100644 index 00000000000..5ac7c0c259a --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/MemberDescriptor.java @@ -0,0 +1,7 @@ +package org.jetbrains.jet.lang.types; + +/** + * @author abreslav + */ +public interface MemberDescriptor { +} diff --git a/idea/src/org/jetbrains/jet/lang/types/MemberDescriptorImpl.java b/idea/src/org/jetbrains/jet/lang/types/MemberDescriptorImpl.java new file mode 100644 index 00000000000..cc530f77185 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/MemberDescriptorImpl.java @@ -0,0 +1,12 @@ +package org.jetbrains.jet.lang.types; + +import java.util.List; + +/** + * @author abreslav + */ +public abstract class MemberDescriptorImpl extends NamedAnnotatedImpl { + public MemberDescriptorImpl(List annotations, String name) { + super(annotations, name); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/NamedAnnotatedImpl.java b/idea/src/org/jetbrains/jet/lang/types/NamedAnnotatedImpl.java new file mode 100644 index 00000000000..2892cb0335e --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/NamedAnnotatedImpl.java @@ -0,0 +1,20 @@ +package org.jetbrains.jet.lang.types; + +import java.util.List; + +/** + * @author abreslav + */ +public abstract class NamedAnnotatedImpl extends AnnotatedImpl { + + private final String name; + + public NamedAnnotatedImpl(List annotations, String name) { + super(annotations); + this.name = name; + } + + public String getName() { + return name; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/NothingType.java b/idea/src/org/jetbrains/jet/lang/types/NothingType.java new file mode 100644 index 00000000000..9659d8de8a3 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/NothingType.java @@ -0,0 +1,41 @@ +package org.jetbrains.jet.lang.types; + +import java.util.*; + +/** + * @author abreslav + */ +public class NothingType extends TypeImpl { + + public static final TypeConstructor NOTHING = new TypeConstructor( + Collections.emptyList(), + "Nothing", + Collections.emptyList(), + new AbstractCollection() { + + @Override + public boolean contains(Object o) { + return o instanceof Type; + } + + @Override + public Iterator iterator() { + throw new UnsupportedOperationException(); + } + + @Override + public int size() { + throw new UnsupportedOperationException(); + } + }); + + // TODO: annotations seem wrong here + public NothingType(List annotations) { + super(annotations, NOTHING, Collections.emptyList()); + } + + @Override + public Collection getMembers() { + return Collections.emptySet(); + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/ParameterDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/ParameterDescriptor.java new file mode 100644 index 00000000000..6519555318e --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/ParameterDescriptor.java @@ -0,0 +1,26 @@ +package org.jetbrains.jet.lang.types; + +import java.util.List; + +/** + * @author abreslav + */ +public class ParameterDescriptor extends AnnotatedImpl { + private final Type type; + private final String name; + + public ParameterDescriptor(List annotations, Type type, String name) { + super(annotations); + this.type = type; + this.name = name; + } + + public Type getType() { + return type; + } + + public String getName() { + return name; + } + +} diff --git a/idea/src/org/jetbrains/jet/lang/types/TupleType.java b/idea/src/org/jetbrains/jet/lang/types/TupleType.java new file mode 100644 index 00000000000..8af202b74a0 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TupleType.java @@ -0,0 +1,82 @@ +package org.jetbrains.jet.lang.types; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author abreslav + */ +public class TupleType extends TypeImpl { + + public static final int TUPLE_COUNT = 22; + private static final TypeConstructor[] TUPLE = new TypeConstructor[TUPLE_COUNT]; + + public static final TupleType UNIT = new TupleType(Collections.emptyList(), Collections.emptyList()); + + static { + for (int i = 0; i < TUPLE_COUNT; i++) { + List parameters = new ArrayList(); + for (int j = 0; j < i; j++) { + parameters.add(new TypeParameterDescriptor( + Collections.emptyList(), + "T" + j, + Variance.OUT_VARIANCE, + Collections.emptySet())); + } + TUPLE[i] = new TypeConstructor( + Collections.emptyList(), + "Tuple" + i, + parameters, + Collections.singleton(JetStandardTypes.getAny())); + } + } + + public static TupleType getTupleType(List annotations, List arguments) { + if (annotations.isEmpty() && arguments.isEmpty()) { + return UNIT; + } + return new TupleType(annotations, arguments); + } + + + public static TupleType getTupleType(List arguments) { + return getTupleType(Collections.emptyList(), arguments); + } + + public static TupleType getLabeledTupleType(List annotations, List arguments) { + return getTupleType(annotations, toTypes(arguments)); + } + + + public static TupleType getLabeledTupleType(List arguments) { + return getLabeledTupleType(Collections.emptyList(), arguments); + } + + + private TupleType(List annotations, List arguments) { + super(annotations, TUPLE[arguments.size()], toProjections(arguments)); + } + + @Override + public Collection getMembers() { + throw new UnsupportedOperationException("Not implemented"); // TODO + } + + private static List toProjections(List arguments) { + List result = new ArrayList(); + for (Type argument : arguments) { + result.add(new TypeProjection(Variance.OUT_VARIANCE, argument)); + } + return result; + } + + private static List toTypes(List labeledEntries) { + List result = new ArrayList(); + for (ParameterDescriptor entry : labeledEntries) { + result.add(entry.getType()); + } + return result; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/Type.java b/idea/src/org/jetbrains/jet/lang/types/Type.java new file mode 100644 index 00000000000..93faf98f626 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/Type.java @@ -0,0 +1,14 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collection; +import java.util.List; + +/** + * @author abreslav + */ +public interface Type extends Annotated { + TypeConstructor getConstructor(); + List getArguments(); + + Collection getMembers(); +} diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java b/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java new file mode 100644 index 00000000000..4577ec0c1f9 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeConstructor.java @@ -0,0 +1,33 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collection; +import java.util.List; + +/** + * @author abreslav + */ +public class TypeConstructor extends AnnotatedImpl { + private final List parameters; + private final Collection supertypes; + private final String debugName; + + public TypeConstructor(List annotations, String debugName, List parameters, Collection supertypes) { + super(annotations); + this.debugName = debugName; + this.parameters = parameters; + this.supertypes = supertypes; + } + + public List getParameters() { + return parameters; + } + + public Collection getSupertypes() { + return supertypes; + } + + @Override + public String toString() { + return debugName; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java b/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java new file mode 100644 index 00000000000..26bfec55684 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeImpl.java @@ -0,0 +1,46 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Iterator; +import java.util.List; + +/** + * @author abreslav + */ +public abstract class TypeImpl extends AnnotatedImpl implements Type { + + private final TypeConstructor constructor; + private final List arguments; + + public TypeImpl(List annotations, TypeConstructor constructor, List arguments) { + super(annotations); + this.constructor = constructor; + this.arguments = arguments; + } + + @Override + public TypeConstructor getConstructor() { + return constructor; + } + + @Override + public List getArguments() { + return arguments; + } + + @Override + public String toString() { + return constructor + (arguments.isEmpty() ? "" : "<" + argumentsToString() + ">"); + } + + private StringBuilder argumentsToString() { + StringBuilder stringBuilder = new StringBuilder(); + for (Iterator iterator = arguments.iterator(); iterator.hasNext();) { + TypeProjection argument = iterator.next(); + stringBuilder.append(argument); + if (iterator.hasNext()) { + stringBuilder.append(", "); + } + } + return stringBuilder; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java b/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java new file mode 100644 index 00000000000..a4e4ee32d38 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeParameterDescriptor.java @@ -0,0 +1,38 @@ +package org.jetbrains.jet.lang.types; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author abreslav + */ +public class TypeParameterDescriptor extends NamedAnnotatedImpl { + private final Variance variance; + private final Collection upperBounds; + private final TypeConstructor typeConstructor; + + public TypeParameterDescriptor(List annotations, String name, Variance variance, Collection upperBounds) { + super(annotations, name); + this.variance = variance; + this.upperBounds = upperBounds; + // TODO: Should we actually pass the annotations on to the type constructor? + this.typeConstructor = new TypeConstructor( + annotations, + name, + Collections.emptyList(), + upperBounds); + } + + public Variance getVariance() { + return variance; + } + + public Collection getUpperBounds() { + return upperBounds; + } + + public TypeConstructor getTypeConstructor() { + return typeConstructor; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeProjection.java b/idea/src/org/jetbrains/jet/lang/types/TypeProjection.java new file mode 100644 index 00000000000..89c498fc417 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeProjection.java @@ -0,0 +1,27 @@ +package org.jetbrains.jet.lang.types; + +/** + * @author abreslav + */ +public class TypeProjection { + private final Variance projection; + private final Type type; + + public TypeProjection(Variance projection, Type type) { + this.projection = projection; + this.type = type; + } + + public Variance getProjection() { + return projection; + } + + public Type getType() { + return type; + } + + @Override + public String toString() { + return projection + " " + type; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java b/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java new file mode 100644 index 00000000000..39f1bcac2ba --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/TypeVariable.java @@ -0,0 +1,22 @@ +package org.jetbrains.jet.lang.types; + + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * @author abreslav + */ +public class TypeVariable extends TypeImpl { + + + public TypeVariable(List annotations, TypeParameterDescriptor typeParameter) { + super(annotations, typeParameter.getTypeConstructor(), Collections.emptyList()); + } + + @Override + public Collection getMembers() { + throw new javax.help.UnsupportedOperationException(); // TODO + } +} diff --git a/idea/src/org/jetbrains/jet/lang/types/Variance.java b/idea/src/org/jetbrains/jet/lang/types/Variance.java new file mode 100644 index 00000000000..fe96885bfff --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/types/Variance.java @@ -0,0 +1,21 @@ +package org.jetbrains.jet.lang.types; + +/** + * @author max + */ +public enum Variance { + INVARIANT(""), + IN_VARIANCE("in"), + OUT_VARIANCE("out"); + + private final String label; + + Variance(String label) { + this.label = label; + } + + @Override + public String toString() { + return label; + } +} diff --git a/idea/tests/org/jetbrains/jet/parsing/JetTypeCheckerTest.java b/idea/tests/org/jetbrains/jet/parsing/JetTypeCheckerTest.java new file mode 100644 index 00000000000..c09949eaf00 --- /dev/null +++ b/idea/tests/org/jetbrains/jet/parsing/JetTypeCheckerTest.java @@ -0,0 +1,82 @@ +package org.jetbrains.jet.parsing; + +import com.intellij.codeInsight.daemon.LightDaemonAnalyzerTestCase; +import com.intellij.openapi.application.PathManager; +import com.intellij.openapi.project.Project; +import org.jetbrains.jet.lang.psi.JetChangeUtil; +import org.jetbrains.jet.lang.psi.JetExpression; +import org.jetbrains.jet.lang.types.JetStandardTypes; +import org.jetbrains.jet.lang.types.Type; +import org.jetbrains.jet.lang.types.JetTypeChecker; + +import java.io.File; + +/** + * @author abreslav + */ +public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase { + + @Override + protected String getTestDataPath() { + return getHomeDirectory() + "/idea/testData"; + } + + private static String getHomeDirectory() { + return new File(PathManager.getResourceRoot(JetParsingTest.class, "/org/jetbrains/jet/parsing/JetParsingTest.class")).getParentFile().getParentFile().getParent(); + } + + public void testConstants() throws Exception { + assertType("1", JetStandardTypes.getInt()); + assertType("0x1", JetStandardTypes.getInt()); + assertType("0X1", JetStandardTypes.getInt()); + assertType("0b1", JetStandardTypes.getInt()); + assertType("0B1", JetStandardTypes.getInt()); + + assertType("1l", JetStandardTypes.getLong()); + assertType("1L", JetStandardTypes.getLong()); + + assertType("1.0", JetStandardTypes.getDouble()); + assertType("1.0d", JetStandardTypes.getDouble()); + assertType("1.0D", JetStandardTypes.getDouble()); + assertType("0x1.fffffffffffffp1023", JetStandardTypes.getDouble()); + + assertType("1.0f", JetStandardTypes.getFloat()); + assertType("1.0F", JetStandardTypes.getFloat()); + assertType("0x1.fffffffffffffp1023f", JetStandardTypes.getFloat()); + + assertType("true", JetStandardTypes.getBoolean()); + assertType("false", JetStandardTypes.getBoolean()); + + assertType("'d'", JetStandardTypes.getChar()); + + assertType("\"d\"", JetStandardTypes.getString()); + assertType("\"\"\"d\"\"\"", JetStandardTypes.getString()); + + assertType("()", JetStandardTypes.getUnit()); + } + + public void testImplicitConversions() throws Exception { + assertConvertibleTo("1", JetStandardTypes.getByte()); + } + + private void assertConvertibleTo(String expression, Type type) { + JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression); + assertTrue( + expression + " must be convertible to " + type, + new JetTypeChecker().isConvertibleTo(jetExpression, type)); + } + + private void assertNotConvertibleTo(String expression, Type type) { + JetExpression jetExpression = JetChangeUtil.createExpression(getProject(), expression); + assertFalse( + expression + " must not be convertible to " + type, + new JetTypeChecker().isConvertibleTo(jetExpression, type)); + } + + private void assertType(String expression, Type expectedType) { + Project project = getProject(); + JetExpression jetExpression = JetChangeUtil.createExpression(project, expression); + Type type = new JetTypeChecker().getType(jetExpression); + assertEquals(type, expectedType); + } +}