Property resolve with substitutions

This commit is contained in:
Andrey Breslav
2011-02-09 17:26:11 +03:00
parent c6964220f0
commit 725ac373ee
11 changed files with 182 additions and 54 deletions
@@ -48,7 +48,7 @@ public class ClassDescriptorResolver {
// TODO : Cache!!!
return new TypeMemberDomain() {
@Override
public PropertyDescriptor getProperty(Type receiverType, @NotNull String name) {
public PropertyDescriptor getProperty(Type contextType, @NotNull String name) {
// TODO : primary constructor parameters
List<JetDeclaration> declarations = classElement.getDeclarations();
for (JetDeclaration declaration : declarations) {
@@ -59,7 +59,7 @@ public class ClassDescriptorResolver {
JetProperty property = (JetProperty) declaration;
if (property.getPropertyTypeRef() != null) {
return resolvePropertyDescriptor(outerScope, property);
return substituteInPropertyDescriptor(contextType, resolvePropertyDescriptor(typeParameterScope, property));
} else {
// TODO : Caution: a cyclic dependency possible
throw new UnsupportedOperationException();
@@ -68,7 +68,7 @@ public class ClassDescriptorResolver {
}
for (Type supertype : supertypes) {
PropertyDescriptor property = supertype.getMemberDomain().getProperty(JetTypeChecker.INSTANCE.substitute(receiverType, supertype), name);
PropertyDescriptor property = supertype.getMemberDomain().getProperty(JetTypeChecker.INSTANCE.substitute(contextType, supertype, Variance.INVARIANT), name);
if (property != null) {
return property;
}
@@ -77,23 +77,30 @@ public class ClassDescriptorResolver {
}
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type, String name) {
public ClassDescriptor getClassDescriptor(@NotNull Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public Collection<MethodDescriptor> getMethods(Type receiverType, String name) {
public Collection<MethodDescriptor> getMethods(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public ExtensionDescriptor getExtension(Type receiverType, String name) {
public ExtensionDescriptor getExtension(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
};
}
private PropertyDescriptor substituteInPropertyDescriptor(Type contextType, PropertyDescriptor propertyDescriptor) {
if (contextType.getConstructor().getParameters().isEmpty()) {
return propertyDescriptor;
}
return new LazySubstitutedPropertyDescriptorImpl(propertyDescriptor, contextType);
}
private static List<TypeParameterDescriptor> resolveTypeParameters(TypeParameterExtensibleScope extensibleScope, List<JetTypeParameter> typeParameters) {
// TODO : When-clause
List<TypeParameterDescriptor> result = new ArrayList<TypeParameterDescriptor>();
@@ -135,7 +142,7 @@ public class ClassDescriptorResolver {
@NotNull
public PropertyDescriptor resolvePropertyDescriptor(@NotNull JetScope scope, @NotNull JetParameter parameter) {
return new PropertyDescriptor(
return new PropertyDescriptorImpl(
AttributeResolver.INSTANCE.resolveAttributes(parameter.getModifierList()),
parameter.getName(),
TypeResolver.INSTANCE.resolveType(scope, parameter.getTypeReference()));
@@ -155,7 +162,7 @@ public class ClassDescriptorResolver {
type = TypeResolver.INSTANCE.resolveType(scope, propertyTypeRef);
}
return new PropertyDescriptor(
return new PropertyDescriptorImpl(
AttributeResolver.INSTANCE.resolveAttributes(property.getModifierList()),
property.getName(),
type);
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
@@ -11,33 +12,81 @@ import java.util.Collections;
public class ErrorType {
private static final TypeMemberDomain ERROR_DOMAIN = new TypeMemberDomain() {
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type, String name) {
public ClassDescriptor getClassDescriptor(@NotNull Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public Collection<MethodDescriptor> getMethods(Type receiverType, String name) {
public Collection<MethodDescriptor> getMethods(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public PropertyDescriptor getProperty(Type receiverType, String name) {
public PropertyDescriptor getProperty(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public ExtensionDescriptor getExtension(Type receiverType, String name) {
public ExtensionDescriptor getExtension(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
};
private static final TypeConstructor ERROR = new TypeConstructor(Collections.<Attribute>emptyList(), false, "ERROR", Collections.<TypeParameterDescriptor>emptyList(), Collections.<Type>emptyList());
private ErrorType() {}
public static Type createErrorType(String debugMessage) {
return new TypeImpl(ERROR, ERROR_DOMAIN);
return createErrorType(debugMessage, ERROR_DOMAIN);
}
public static boolean isError(Type type) {
return type.getConstructor() == ERROR;
private static Type createErrorType(String debugMessage, TypeMemberDomain memberDomain) {
return new ErrorTypeImpl(new TypeConstructor(Collections.<Attribute>emptyList(), false, "[ERROR : " + debugMessage + "]", Collections.<TypeParameterDescriptor>emptyList(), Collections.<Type>emptyList()), memberDomain);
}
public static Type createWrongVarianceErrorType(TypeProjection value) {
return createErrorType(value + " is not allowed here]", value.getType().getMemberDomain());
}
public static boolean isErrorType(Type type) {
return type instanceof ErrorTypeImpl;
}
private static class ErrorTypeImpl implements Type {
private final TypeConstructor constructor;
private final TypeMemberDomain memberDomain;
private ErrorTypeImpl(TypeConstructor constructor, TypeMemberDomain memberDomain) {
this.constructor = constructor;
this.memberDomain = memberDomain;
}
@NotNull
@Override
public TypeConstructor getConstructor() {
return constructor;
}
@NotNull
@Override
public List<TypeProjection> getArguments() {
return Collections.emptyList();
}
@Override
public boolean isNullable() {
return false;
}
@NotNull
@Override
public TypeMemberDomain getMemberDomain() {
return memberDomain;
}
@Override
public List<Attribute> getAttributes() {
return Collections.emptyList();
}
}
}
@@ -48,23 +48,23 @@ public class JetStandardClasses {
public static final TypeMemberDomain STUB = new TypeMemberDomain() {
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type, String name) {
public ClassDescriptor getClassDescriptor(@NotNull Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public Collection<MethodDescriptor> getMethods(Type receiverType, String name) {
public Collection<MethodDescriptor> getMethods(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public PropertyDescriptor getProperty(Type receiverType, String name) {
public PropertyDescriptor getProperty(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
@Override
public ExtensionDescriptor getExtension(Type receiverType, String name) {
public ExtensionDescriptor getExtension(Type contextType, String name) {
throw new UnsupportedOperationException(); // TODO
}
};
@@ -235,7 +235,7 @@ public class JetTypeChecker {
Collection<? extends Type> supertypes = thisType.getConstructor().getSupertypes();
for (Type declaredSupertype : supertypes) {
if (declaredSupertype.getConstructor().equals(superclass.getTypeConstructor())) {
result[0] = substituteInType(getSubstitutionContext(thisType), declaredSupertype);
result[0] = substituteInType(getSubstitutionContext(thisType), declaredSupertype, Variance.INVARIANT);
break;
}
}
@@ -521,7 +521,7 @@ public class JetTypeChecker {
if (visited.contains(supertypeConstructor)) {
continue;
}
Type substitutedSupertype = substituteInType(substitutionContext, supertype);
Type substitutedSupertype = substituteInType(substitutionContext, supertype, Variance.INVARIANT);
dfs(substitutedSupertype, visited, handler);
}
handler.afterChildren(current);
@@ -557,7 +557,7 @@ public class JetTypeChecker {
for (Type immediateSupertype : constructor.getSupertypes()) {
Type correspondingSupertype = findCorrespondingSupertype(immediateSupertype, supertype);
if (correspondingSupertype != null) {
return substituteInType(getSubstitutionContext(subtype), correspondingSupertype);
return substituteInType(getSubstitutionContext(subtype), correspondingSupertype, Variance.INVARIANT);
}
}
return null;
@@ -576,9 +576,16 @@ public class JetTypeChecker {
return parameterValues;
}
private Type substituteInType(Map<TypeConstructor, TypeProjection> substitutionContext, Type type) {
private Type substituteInType(Map<TypeConstructor, TypeProjection> substitutionContext, Type type, Variance howThisTypeIsUsed) {
TypeProjection value = substitutionContext.get(type.getConstructor());
assert value == null : "For now this is used only for supertypes, thus no variables";
if (value != null) {
Variance projectionKind = value.getProjectionKind();
if (howThisTypeIsUsed.allowsInPosition() && !projectionKind.allowsInPosition()
|| howThisTypeIsUsed.allowsOutPosition() && !projectionKind.allowsOutPosition()) {
return ErrorType.createWrongVarianceErrorType(value);
}
return value.getType();
}
return specializeType(type, substituteInArguments(substitutionContext, type));
}
@@ -603,8 +610,8 @@ public class JetTypeChecker {
}
@NotNull
public Type substitute(@NotNull Type context, @NotNull Type subject) {
return substituteInType(getSubstitutionContext(context), subject);
public Type substitute(@NotNull Type context, @NotNull Type subject, @NotNull Variance howThisTypeIsUsed) {
return substituteInType(getSubstitutionContext(context), subject, howThisTypeIsUsed);
}
private Type specializeType(Type type, List<TypeProjection> newArguments) {
@@ -0,0 +1,36 @@
package org.jetbrains.jet.lang.types;
import java.util.List;
/**
* @author abreslav
*/
public class LazySubstitutedPropertyDescriptorImpl implements PropertyDescriptor {
private final PropertyDescriptor propertyDescriptor;
private final Type contextType;
private Type propertyType = null;
public LazySubstitutedPropertyDescriptorImpl(PropertyDescriptor propertyDescriptor, Type contextType) {
this.propertyDescriptor = propertyDescriptor;
this.contextType = contextType;
}
@Override
public Type getType() {
if (propertyType == null) {
propertyType = JetTypeChecker.INSTANCE.substitute(contextType, propertyDescriptor.getType(), Variance.OUT_VARIANCE);
}
return propertyType;
}
@Override
public List<Attribute> getAttributes() {
// TODO : Substitute, lazily
return propertyDescriptor.getAttributes();
}
@Override
public String getName() {
return propertyDescriptor.getName();
}
}
@@ -0,0 +1,8 @@
package org.jetbrains.jet.lang.types;
/**
* @author abreslav
*/
public interface Named {
String getName();
}
@@ -5,7 +5,7 @@ import java.util.List;
/**
* @author abreslav
*/
public abstract class NamedAnnotatedImpl extends AnnotatedImpl {
public abstract class NamedAnnotatedImpl extends AnnotatedImpl implements Named {
private final String name;
@@ -14,6 +14,7 @@ public abstract class NamedAnnotatedImpl extends AnnotatedImpl {
this.name = name;
}
@Override
public String getName() {
return name;
}
@@ -1,23 +1,8 @@
package org.jetbrains.jet.lang.types;
import java.util.List;
/**
* @author abreslav
*/
public class PropertyDescriptor extends MemberDescriptorImpl {
private Type type;
public PropertyDescriptor(List<Attribute> attributes, String name, Type type) {
super(attributes, name);
this.type = type;
}
public PropertyDescriptor(List<Attribute> attributes, String name) {
this(attributes, name, null);
}
public Type getType() {
return type;
}
public interface PropertyDescriptor extends Annotated, Named {
Type getType();
}
@@ -0,0 +1,24 @@
package org.jetbrains.jet.lang.types;
import java.util.List;
/**
* @author abreslav
*/
public class PropertyDescriptorImpl extends MemberDescriptorImpl implements PropertyDescriptor {
private Type type;
public PropertyDescriptorImpl(List<Attribute> attributes, String name, Type type) {
super(attributes, name);
this.type = type;
}
public PropertyDescriptorImpl(List<Attribute> attributes, String name) {
this(attributes, name, null);
}
@Override
public Type getType() {
return type;
}
}
@@ -12,36 +12,36 @@ import java.util.Collections;
public interface TypeMemberDomain {
TypeMemberDomain EMPTY = new TypeMemberDomain() {
@Override
public ClassDescriptor getClassDescriptor(@NotNull Type type, String name) {
public ClassDescriptor getClassDescriptor(@NotNull Type contextType, String name) {
return null;
}
@NotNull
@Override
public Collection<MethodDescriptor> getMethods(Type receiverType, String name) {
public Collection<MethodDescriptor> getMethods(Type contextType, String name) {
return Collections.emptyList();
}
@Override
public PropertyDescriptor getProperty(Type receiverType, String name) {
public PropertyDescriptor getProperty(Type contextType, String name) {
return null;
}
@Override
public ExtensionDescriptor getExtension(Type receiverType, String name) {
public ExtensionDescriptor getExtension(Type contextType, String name) {
return null;
}
};
@Nullable
ClassDescriptor getClassDescriptor(@NotNull Type type, String name);
ClassDescriptor getClassDescriptor(@NotNull Type contextType, String name);
@NotNull
Collection<MethodDescriptor> getMethods(Type receiverType, String name);
Collection<MethodDescriptor> getMethods(Type contextType, String name);
@Nullable
PropertyDescriptor getProperty(Type receiverType, String name);
PropertyDescriptor getProperty(Type contextType, String name);
@Nullable
ExtensionDescriptor getExtension(Type receiverType, String name);
ExtensionDescriptor getExtension(Type contextType, String name);
}
@@ -310,6 +310,9 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
public void testPropertiesInClasses() throws Exception {
assertType("new Properties().p", "Int");
assertType("new Props<Int>().p", "Int");
assertType("new Props<out Int>().p", "Int");
assertErrorType("new Props<in Int>().p");
}
// public void testImplicitConversions() throws Exception {
@@ -364,6 +367,13 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
assertTrue(type + " != " + expectedType, JetTypeChecker.INSTANCE.equalTypes(type, expectedType));
}
private void assertErrorType(String expression) {
Project project = getProject();
JetExpression jetExpression = JetChangeUtil.createExpression(project, expression);
Type type = JetTypeChecker.INSTANCE.getType(ClassDefinitions.BASIC_SCOPE, jetExpression, false);
assertTrue("Error type expected but " + type + " returned", ErrorType.isErrorType(type));
}
private static void assertType(String contextType, String expression, String expectedType) {
final Type thisType = makeType(contextType);
JetScope scope = new JetScopeAdapter(ClassDefinitions.BASIC_SCOPE) {
@@ -407,7 +417,8 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
"open class Derived_inT<in T> : Base_inT<T>",
"open class Base_outT<out T>",
"open class Derived_outT<out T> : Base_outT<T>",
"class Properties { val p : Int }"
"class Properties { val p : Int }",
"class Props<T> { val p : T }",
};
public static JetScope BASIC_SCOPE = new JetScopeAdapter(JetStandardClasses.STANDARD_CLASSES) {