Property resolve with substitutions
This commit is contained in:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user