Basic user type test passes

This commit is contained in:
Andrey Breslav
2011-01-26 17:48:02 +03:00
parent a60a512dc9
commit 1a6f7f5f79
13 changed files with 209 additions and 37 deletions
+1 -1
View File
@@ -123,7 +123,7 @@ public interface JetNodeTypes {
JetNodeType WHEN_CONDITION = new JetNodeType("WHEN_CONDITION");
JetNodeType TUPLE_PATTERN_ENTRY = new JetNodeType("TUPLE_PATTERN_ENTRY");
JetNodeType NULLABLE_TYPE = new JetNodeType("NULLABLE_TYPE", JetNullableType.class);
JetNodeType TYPE_PROJECTION = new JetNodeType("TYPE_PROJECTION");
JetNodeType TYPE_PROJECTION = new JetNodeType("TYPE_PROJECTION", JetTypeProjection.class);
JetNodeType NAMESPACE_NAME = new JetNodeType("NAMESPACE_NAME", JetContainerNode.class);
}
@@ -45,8 +45,8 @@ public class JetCallExpression extends JetExpression {
}
@NotNull
public List<JetTypeReference> getTypeArguments() {
public List<JetTypeProjection> getTypeArguments() {
JetTypeArgumentList list = getTypeArgumentList();
return list != null ? list.getArguments() : Collections.<JetTypeReference>emptyList();
return list != null ? list.getArguments() : Collections.<JetTypeProjection>emptyList();
}
}
@@ -23,6 +23,10 @@ public class JetChangeUtil {
return property.getPropertyTypeRef();
}
public static JetClass createClass(Project project, String text) {
return createDeclaration(project, text, JetClass.class);
}
@NotNull
public static JetFile createFile(Project project, String text) {
return (JetFile) PsiFileFactory.getInstance(project).createFileFromText("dummy.jet", JetFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true);
@@ -34,11 +38,16 @@ public class JetChangeUtil {
}
private static JetProperty createProperty(Project project, String text) {
return createDeclaration(project, text, JetProperty.class);
}
private static <T> T createDeclaration(Project project, String text, Class<T> clazz) {
JetFile file = createFile(project, text);
JetNamespace rootNamespace = file.getRootNamespace();
List<JetDeclaration> dcls = rootNamespace.getDeclarations();
assert dcls.size() == 1;
return (JetProperty) dcls.get(0);
//noinspection unchecked
return (T) dcls.get(0);
}
public static PsiElement createNameIdentifier(Project project, String name) {
@@ -19,7 +19,7 @@ public class JetTypeArgumentList extends JetElement {
visitor.visitTypeArgumentList(this);
}
public List<JetTypeReference> getArguments() {
return findChildrenByType(JetNodeTypes.TYPE_REFERENCE);
public List<JetTypeProjection> getArguments() {
return findChildrenByType(JetNodeTypes.TYPE_PROJECTION);
}
}
@@ -0,0 +1,45 @@
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;
import org.jetbrains.jet.lang.types.ProjectionKind;
import org.jetbrains.jet.lexer.JetTokens;
/**
* @author abreslav
*/
public class JetTypeProjection extends JetDeclaration {
public JetTypeProjection(@NotNull ASTNode node) {
super(node);
}
@NotNull
public ProjectionKind getProjectionKind() {
JetModifierList modifierList = getModifierList();
if (modifierList != null) {
if (modifierList.hasModifier(JetTokens.IN_KEYWORD)) {
return ProjectionKind.IN_ONLY;
}
if (modifierList.hasModifier(JetTokens.OUT_KEYWORD)) {
return ProjectionKind.OUT_ONLY;
}
}
if (findChildByType(JetTokens.MUL) != null) {
return ProjectionKind.NEITHER_OUT_NOR_IN;
}
return ProjectionKind.NO_PROJECTION;
}
@Override
public void accept(@NotNull JetVisitor visitor) {
visitor.visitTypeProjection(this);
}
@Nullable
public JetTypeReference getTypeReference() {
return (JetTypeReference) findChildByType(JetNodeTypes.TYPE_REFERENCE);
}
}
@@ -29,16 +29,6 @@ public class JetTypeReference extends JetElement {
return findChildByClass(JetTypeElement.class);
}
public JetTypeArgumentList getTypeArgumentList() {
return findChildByClass(JetTypeArgumentList.class);
}
public List<JetTypeReference> getTypeArguments() {
// TODO: empty elements in PSI
JetTypeArgumentList typeArgumentList = getTypeArgumentList();
return typeArgumentList == null ? Collections.<JetTypeReference>emptyList() : typeArgumentList.getArguments();
}
public List<JetAttribute> getAttributes() {
List<JetAttribute> answer = null;
for (JetAttributeAnnotation annotation : getAttributeAnnotations()) {
@@ -4,6 +4,9 @@ import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetNodeTypes;
import java.util.Collections;
import java.util.List;
/**
* @author max
*/
@@ -17,6 +20,16 @@ public class JetUserType extends JetTypeElement {
visitor.visitUserType(this);
}
public JetTypeArgumentList getTypeArgumentList() {
return (JetTypeArgumentList) findChildByType(JetNodeTypes.TYPE_ARGUMENT_LIST);
}
public List<JetTypeProjection> getTypeArguments() {
// TODO: empty elements in PSI
JetTypeArgumentList typeArgumentList = getTypeArgumentList();
return typeArgumentList == null ? Collections.<JetTypeProjection>emptyList() : typeArgumentList.getArguments();
}
public JetReferenceExpression getReferenceExpression() {
return (JetReferenceExpression) findChildByType(JetNodeTypes.REFERENCE_EXPRESSION);
}
@@ -325,4 +325,8 @@ public class JetVisitor extends PsiElementVisitor {
public void visitNullableType(JetNullableType nullableType) {
visitTypeElement(nullableType);
}
public void visitTypeProjection(JetTypeProjection typeProjection) {
visitJetElement(typeProjection);
}
}
@@ -12,7 +12,7 @@ public class ClassType extends TypeImpl {
public ClassType(List<Annotation> annotations, ClassDescriptor classDescriptor, List<TypeProjection> arguments) {
super(annotations, classDescriptor.getTypeConstructor(), arguments);
assert classDescriptor.getTypeConstructor().getParameters().size() == arguments.size();
assert classDescriptor.getTypeConstructor().getParameters().size() == arguments.size() : classDescriptor.getTypeConstructor().getParameters().size() + " != " + arguments.size();
this.classDescriptor = classDescriptor;
}
@@ -37,8 +37,7 @@ public class JetStandardClasses {
for (int j = 0; j < i; j++) {
parameters.add(new TypeParameterDescriptor(
Collections.<Annotation>emptyList(),
"T" + j,
Variance.OUT_VARIANCE,
Variance.OUT_VARIANCE, "T" + j,
Collections.<Type>emptySet()));
}
TUPLE[i] = new ClassDescriptor(
@@ -138,7 +138,7 @@ public class JetTypeChecker {
case INVARIANT:
switch (superArgument.getProjectionKind()) {
case NO_PROJECTION:
if (!subArgumentType.equals(superArgumentType)) {
if (!equalTypes(subArgumentType, superArgumentType)) {
return false;
}
break;
@@ -199,4 +199,26 @@ public class JetTypeChecker {
return true;
}
private boolean equalTypes(Type type1, Type type2) {
if (!type1.getConstructor().equals(type2.getConstructor())) {
return false;
}
List<TypeProjection> type1Arguments = type1.getArguments();
List<TypeProjection> type2Arguments = type2.getArguments();
if (type1Arguments.size() != type2Arguments.size()) {
return false;
}
for (int i = 0; i < type1Arguments.size(); i++) {
TypeProjection typeProjection1 = type1Arguments.get(i);
TypeProjection typeProjection2 = type2Arguments.get(i);
if (typeProjection1.getProjectionKind() != typeProjection2.getProjectionKind()) {
return false;
}
if (!equalTypes(typeProjection1.getType(), typeProjection2.getType())) {
return false;
}
}
return true;
}
}
@@ -12,7 +12,7 @@ public class TypeParameterDescriptor extends NamedAnnotatedImpl {
private final Collection<Type> upperBounds;
private final TypeConstructor typeConstructor;
public TypeParameterDescriptor(List<Annotation> annotations, String name, Variance variance, Collection<Type> upperBounds) {
public TypeParameterDescriptor(List<Annotation> annotations, Variance variance, String name, Collection<Type> upperBounds) {
super(annotations, name);
this.variance = variance;
this.upperBounds = upperBounds;
@@ -10,14 +10,32 @@ import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.parsing.JetParsingTest;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
/**
* @author abreslav
*/
public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public static final ClassDescriptor BASE_T = new ClassDescriptor(
Collections.<Annotation>emptyList(),
"Base_T",
Arrays.asList(
new TypeParameterDescriptor(
Collections.<Annotation>emptyList(),
Variance.INVARIANT, "T",
Collections.<Type>emptyList())
),
Collections.singleton(JetStandardClasses.getAnyType())
);
private static Map<String, ClassDescriptor> CLASSES = new HashMap<String, ClassDescriptor>();
private static String[] CLASS_DECLARATIONS = {
"class Base_T<T>",
"class Base_inT<in T>",
"class Base_outT<out T>",
};
private static final JetScope BASIC_SCOPE = new JetScope.JetScopeImpl() {
@Override
public ClassDescriptor getClass(String name) {
@@ -42,11 +60,23 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
} else if ("Any".equals(name)) {
return JetStandardClasses.getAny();
}
if (CLASSES.isEmpty()) {
for (String classDeclaration : CLASS_DECLARATIONS) {
JetClass classElement = JetChangeUtil.createClass(getProject(), classDeclaration);
ClassDescriptor classDescriptor = toClassDescriptor(classElement);
CLASSES.put(classDescriptor.getName(), classDescriptor);
}
}
ClassDescriptor classDescriptor = CLASSES.get(name);
if (classDescriptor != null) {
return classDescriptor;
}
fail("Type not found: " + name);
throw new IllegalStateException();
}
};
@Override
protected String getTestDataPath() {
return getHomeDirectory() + "/idea/testData";
@@ -86,7 +116,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertType("()", JetStandardTypes.getUnit());
}
public void testSubtyping() throws Exception {
public void testBasicSubtyping() throws Exception {
assertSubtype("Boolean", "Boolean");
assertSubtype("Byte", "Byte");
assertSubtype("Char", "Char");
@@ -149,18 +179,59 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertSubtype("(Unit, Unit)", "(Any, Any)");
assertSubtype("(Unit, Unit)", "(Any, Unit)");
assertSubtype("(Unit, Unit)", "(Unit, Any)");
}
private void assertSubtype(String type1, String type2) {
public void testProjections() throws Exception {
assertSubtype("Base_T<Int>", "Base_T<Int>");
}
public void testImplicitConversions() throws Exception {
assertConvertibleTo("1", JetStandardTypes.getByte());
}
private static ClassDescriptor toClassDescriptor(JetClass classElement) {
return new ClassDescriptor(
toAttributes(classElement.getModifierList()),
classElement.getName(),
toTypeParameters(classElement.getTypeParameters()),
toTypes(classElement.getDelegationSpecifiers())
);
}
private static List<TypeParameterDescriptor> toTypeParameters(List<JetTypeParameter> typeParameters) {
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
for (JetTypeParameter typeParameter : typeParameters) {
result.add(toTypeParameter(typeParameter));
}
return result;
}
private static TypeParameterDescriptor toTypeParameter(JetTypeParameter typeParameter) {
JetTypeReference extendsBound = typeParameter.getExtendsBound();
return new TypeParameterDescriptor(
toAttributes(typeParameter.getModifierList()),
typeParameter.getVariance(),
typeParameter.getName(),
extendsBound == null ? Collections.<Type>singleton(JetStandardClasses.getAnyType()) : Collections.singleton(toType(extendsBound))
);
}
private static Collection<? extends Type> toTypes(List<JetDelegationSpecifier> delegationSpecifiers) {
if (delegationSpecifiers.isEmpty()) {
return Collections.emptyList();
}
throw new UnsupportedOperationException(); // TODO
}
private static void assertSubtype(String type1, String type2) {
assertSubtypingRelation(type1, type2, true);
}
private void assertNotSubtype(String type1, String type2) {
private static void assertNotSubtype(String type1, String type2) {
assertSubtypingRelation(type1, type2, false);
}
private void assertSubtypingRelation(String type1, String type2, boolean expected) {
private static void assertSubtypingRelation(String type1, String type2, boolean expected) {
Type typeNode1 = toType(JetChangeUtil.createType(getProject(), type1));
Type typeNode2 = toType(JetChangeUtil.createType(getProject(), type2));
boolean result = new JetTypeChecker().isSubtypeOf(
@@ -170,19 +241,20 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertTrue(typeNode1 + " is " + modifier + "a subtype of " + typeNode2, result == expected);
}
private Type toType(JetTypeReference typeNode) {
List<JetAttribute> attributes = typeNode.getAttributes();
private static Type toType(JetTypeReference typeNode) {
List<JetAttribute> attributeElements = typeNode.getAttributes();
final List<Annotation> attributes = toAttributes(attributeElements);
JetTypeElement typeElement = typeNode.getTypeElement();
List<JetTypeReference> argumentElements = typeNode.getTypeArguments();
final List<Type> arguments = toTypes(argumentElements);
// TODO annotations
final Type[] result = new Type[1];
typeElement.accept(new JetVisitor() {
@Override
public void visitUserType(JetUserType type) {
result[0] = new ClassType(TypeResolver.INSTANCE.resolveClass(BASIC_SCOPE, type));
List<JetTypeProjection> argumentElements = type.getTypeArguments();
final List<TypeProjection> arguments = toTypeProjections(argumentElements);
result[0] = new ClassType(attributes, TypeResolver.INSTANCE.resolveClass(BASIC_SCOPE, type), arguments);
}
@Override
@@ -200,7 +272,19 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
return result[0];
}
private List<Type> toTypes(List<JetTypeReference> argumentElements) {
private static List<Annotation> toAttributes(List<JetAttribute> attributeElements) {
return Collections.emptyList();
}
private static List<Annotation> toAttributes(JetModifierList modifierList) {
if (modifierList == null) {
return Collections.emptyList();
}
// TODO:
return Collections.emptyList();
}
private static List<Type> toTypes(List<JetTypeReference> argumentElements) {
final List<Type> arguments = new ArrayList<Type>();
for (JetTypeReference argumentElement : argumentElements) {
arguments.add(toType(argumentElement));
@@ -208,8 +292,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
return arguments;
}
public void testImplicitConversions() throws Exception {
assertConvertibleTo("1", JetStandardTypes.getByte());
private static List<TypeProjection> toTypeProjections(List<JetTypeProjection> argumentElements) {
final List<TypeProjection> arguments = new ArrayList<TypeProjection>();
for (JetTypeProjection argumentElement : argumentElements) {
Type type = toType(argumentElement.getTypeReference());
TypeProjection typeProjection = new TypeProjection(argumentElement.getProjectionKind(), type);
arguments.add(typeProjection);
}
return arguments;
}
private static void assertConvertibleTo(String expression, Type type) {