Correct descriptors for properties with receivers

This commit is contained in:
Andrey Breslav
2011-05-20 17:42:59 +04:00
parent 805123f4a1
commit 3e0141ada4
7 changed files with 107 additions and 31 deletions
@@ -1,5 +1,6 @@
package org.jetbrains.jet.lang.descriptors; package org.jetbrains.jet.lang.descriptors;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
@@ -15,6 +16,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
private final MemberModifiers memberModifiers; private final MemberModifiers memberModifiers;
private final boolean isVar; private final boolean isVar;
private final JetType receiverType;
private final List<TypeParameterDescriptor> typeParemeters = Lists.newArrayListWithCapacity(0);
private PropertyGetterDescriptor getter; private PropertyGetterDescriptor getter;
private PropertySetterDescriptor setter; private PropertySetterDescriptor setter;
@@ -23,35 +26,51 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
@NotNull List<Annotation> annotations, @NotNull List<Annotation> annotations,
@NotNull MemberModifiers memberModifiers, @NotNull MemberModifiers memberModifiers,
boolean isVar, boolean isVar,
@Nullable JetType receiverType,
@NotNull String name, @NotNull String name,
@Nullable JetType inType, @Nullable JetType inType,
@Nullable JetType outType) { @NotNull JetType outType) {
super(containingDeclaration, annotations, name, inType, outType); super(containingDeclaration, annotations, name, inType, outType);
assert !isVar || inType != null; assert !isVar || inType != null;
assert outType != null; // assert outType != null;
this.isVar = isVar; this.isVar = isVar;
this.memberModifiers = memberModifiers; this.memberModifiers = memberModifiers;
this.receiverType = receiverType;
} }
public PropertyDescriptor( private PropertyDescriptor(
@NotNull PropertyDescriptor original, @NotNull PropertyDescriptor original,
@Nullable JetType receiverType,
@Nullable JetType inType, @Nullable JetType inType,
@Nullable JetType outType) { @NotNull JetType outType) {
this( this(
original.getContainingDeclaration(), original.getContainingDeclaration(),
original.getAnnotations(), // TODO : substitute? original.getAnnotations(), // TODO : substitute?
original.getModifiers(), original.getModifiers(),
original.isVar, original.isVar,
receiverType,
original.getName(), original.getName(),
inType, inType,
outType); outType);
} }
public void initialize(@Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) { public void initialize(@NotNull List<TypeParameterDescriptor> typeParameters, @Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) {
this.typeParemeters.addAll(typeParameters);
this.getter = getter; this.getter = getter;
this.setter = setter; this.setter = setter;
} }
@NotNull
public List<TypeParameterDescriptor> getTypeParemeters() {
return typeParemeters;
}
@Nullable
public JetType getReceiverType() {
return receiverType;
}
public boolean isVar() { public boolean isVar() {
return isVar; return isVar;
} }
@@ -78,12 +97,14 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member
JetType originalInType = getInType(); JetType originalInType = getInType();
JetType inType = originalInType == null ? null : substitutor.substitute(originalInType, Variance.IN_VARIANCE); JetType inType = originalInType == null ? null : substitutor.substitute(originalInType, Variance.IN_VARIANCE);
JetType originalOutType = getOutType(); JetType originalOutType = getOutType();
JetType outType = originalOutType == null ? null : substitutor.substitute(originalOutType, Variance.OUT_VARIANCE); JetType outType = substitutor.substitute(originalOutType, Variance.OUT_VARIANCE);
if (inType == null && outType == null) { if (inType == null && outType == null) {
return null; // TODO : tell the user that the property was projected out return null; // TODO : tell the user that the property was projected out
} }
JetType receiverType = getReceiverType();
return new PropertyDescriptor( return new PropertyDescriptor(
this, this,
receiverType == null ? null : substitutor.substitute(receiverType, Variance.IN_VARIANCE),
inType, inType,
outType outType
); );
@@ -14,7 +14,7 @@ import java.util.List;
/** /**
* @author max * @author max
*/ */
public class JetProperty extends JetNamedDeclaration { public class JetProperty extends JetTypeParameterListOwner {
public JetProperty(@NotNull ASTNode node) { public JetProperty(@NotNull ASTNode node) {
super(node); super(node);
} }
@@ -44,7 +44,6 @@ public class JetProperty extends JetNamedDeclaration {
return null; return null;
} }
@Nullable @Nullable
public JetTypeReference getPropertyTypeRef() { public JetTypeReference getPropertyTypeRef() {
ASTNode node = getNode().getFirstChildNode(); ASTNode node = getNode().getFirstChildNode();
@@ -358,22 +358,45 @@ public class ClassDescriptorResolver {
@NotNull @NotNull
public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) { public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) {
JetType type = getType(scope, property, true);
boolean isVar = property.isVar(); JetScope scopeWithTypeParameters;
List<TypeParameterDescriptor> typeParameterDescriptors;
List<JetTypeParameter> typeParameters = property.getTypeParameters();
if (typeParameters.isEmpty()) {
scopeWithTypeParameters = scope;
typeParameterDescriptors = Collections.emptyList();
}
else {
WritableScope writableScope = new WritableScopeImpl(scope, containingDeclaration, trace.getErrorHandler());
typeParameterDescriptors = resolveTypeParameters(containingDeclaration, writableScope, typeParameters);
scopeWithTypeParameters = writableScope;
}
JetType receiverType = null;
JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
if (receiverTypeRef != null) {
receiverType = typeResolver.resolveType(scopeWithTypeParameters, receiverTypeRef);
}
JetModifierList modifierList = property.getModifierList(); JetModifierList modifierList = property.getModifierList();
boolean isVar = property.isVar();
JetType type = getType(scopeWithTypeParameters, property, true);
PropertyDescriptor propertyDescriptor = new PropertyDescriptor( PropertyDescriptor propertyDescriptor = new PropertyDescriptor(
containingDeclaration, containingDeclaration,
AnnotationResolver.INSTANCE.resolveAnnotations(modifierList), AnnotationResolver.INSTANCE.resolveAnnotations(modifierList),
resolveModifiers(modifierList, DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts resolveModifiers(modifierList, DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts
isVar, isVar,
receiverType,
JetPsiUtil.safeName(property.getName()), JetPsiUtil.safeName(property.getName()),
isVar ? type : null, isVar ? type : null,
type); type);
propertyDescriptor.initialize( propertyDescriptor.initialize(
resolvePropertyGetterDescriptor(scope, property, propertyDescriptor), typeParameterDescriptors,
resolvePropertySetterDescriptor(scope, property, propertyDescriptor)); resolvePropertyGetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor),
resolvePropertySetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor));
trace.recordDeclarationResolution(property, propertyDescriptor); trace.recordDeclarationResolution(property, propertyDescriptor);
return propertyDescriptor; return propertyDescriptor;
@@ -384,14 +407,12 @@ public class ClassDescriptorResolver {
// TODO : receiver? // TODO : receiver?
JetTypeReference propertyTypeRef = property.getPropertyTypeRef(); JetTypeReference propertyTypeRef = property.getPropertyTypeRef();
JetType type;
if (propertyTypeRef == null) { if (propertyTypeRef == null) {
final JetExpression initializer = property.getInitializer(); final JetExpression initializer = property.getInitializer();
if (initializer == null) { if (initializer == null) {
trace.getErrorHandler().genericError(property.getNode(), "This property must either have a type annotation or be initialized"); trace.getErrorHandler().genericError(property.getNode(), "This property must either have a type annotation or be initialized");
type = ErrorUtils.createErrorType("No type, no body"); return ErrorUtils.createErrorType("No type, no body");
} else { } else {
// TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}"
// TODO : a risk of a memory leak // TODO : a risk of a memory leak
LazyValue<JetType> lazyValue = new LazyValue<JetType>() { LazyValue<JetType> lazyValue = new LazyValue<JetType>() {
@Override @Override
@@ -400,16 +421,15 @@ public class ClassDescriptorResolver {
} }
}; };
if (allowDeferred) { if (allowDeferred) {
type = new DeferredType(lazyValue); return new DeferredType(lazyValue);
} }
else { else {
type = lazyValue.get(); return lazyValue.get();
} }
} }
} else { } else {
type = typeResolver.resolveType(scope, propertyTypeRef); return typeResolver.resolveType(scope, propertyTypeRef);
} }
return type;
} }
@NotNull @NotNull
@@ -551,10 +571,11 @@ public class ClassDescriptorResolver {
AnnotationResolver.INSTANCE.resolveAnnotations(modifierList), AnnotationResolver.INSTANCE.resolveAnnotations(modifierList),
resolveModifiers(modifierList, DEFAULT_MODIFIERS), resolveModifiers(modifierList, DEFAULT_MODIFIERS),
isMutable, isMutable,
null,
name == null ? "<no name>" : name, name == null ? "<no name>" : name,
isMutable ? type : null, isMutable ? type : null,
type); type);
propertyDescriptor.initialize(null, null); propertyDescriptor.initialize(Collections.<TypeParameterDescriptor>emptyList(), null, null);
trace.recordValueParameterAsPropertyResolution(parameter, propertyDescriptor); trace.recordValueParameterAsPropertyResolution(parameter, propertyDescriptor);
return propertyDescriptor; return propertyDescriptor;
} }
@@ -92,6 +92,7 @@ public class JavaClassMembersScope implements JetScope {
Collections.<Annotation>emptyList(), Collections.<Annotation>emptyList(),
new MemberModifiers(false, false, false), new MemberModifiers(false, false, false),
!isFinal, !isFinal,
null,
field.getName(), field.getName(),
isFinal ? null : type, isFinal ? null : type,
type); type);
@@ -100,7 +100,13 @@ public class ErrorUtils {
private static final JetType ERROR_PROPERTY_TYPE = createErrorType("<ERROR PROPERTY TYPE>"); private static final JetType ERROR_PROPERTY_TYPE = createErrorType("<ERROR PROPERTY TYPE>");
private static final VariableDescriptor ERROR_PROPERTY = new PropertyDescriptor( private static final VariableDescriptor ERROR_PROPERTY = new PropertyDescriptor(
ERROR_CLASS, Collections.<Annotation>emptyList(), new MemberModifiers(false, false, false), true, "<ERROR PROPERTY>", ERROR_PROPERTY_TYPE, ERROR_PROPERTY_TYPE); ERROR_CLASS,
Collections.<Annotation>emptyList(),
new MemberModifiers(false, false, false),
true,
null,
"<ERROR PROPERTY>",
ERROR_PROPERTY_TYPE, ERROR_PROPERTY_TYPE);
private static FunctionDescriptor createErrorFunction(List<TypeParameterDescriptor> typeParameters, List<JetType> positionedValueArgumentTypes) { private static FunctionDescriptor createErrorFunction(List<TypeParameterDescriptor> typeParameters, List<JetType> positionedValueArgumentTypes) {
FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(ERROR_CLASS, Collections.<Annotation>emptyList(), "<ERROR FUNCTION>"); FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(ERROR_CLASS, Collections.<Annotation>emptyList(), "<ERROR FUNCTION>");
@@ -883,8 +883,6 @@ public class JetTypeInferrer {
} }
} }
@Override @Override
public void visitTupleExpression(JetTupleExpression expression) { public void visitTupleExpression(JetTupleExpression expression) {
List<JetExpression> entries = expression.getEntries(); List<JetExpression> entries = expression.getEntries();
@@ -1019,7 +1017,10 @@ public class JetTypeInferrer {
@Override @Override
public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) { public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) {
checkPatternType(condition.getPattern(), finalSubjectType); JetPattern pattern = condition.getPattern();
if (pattern != null) {
checkPatternType(pattern, finalSubjectType);
}
} }
@Override @Override
@@ -1,9 +1,12 @@
package org.jetbrains.jet.resolve; package org.jetbrains.jet.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.types.*; import org.jetbrains.jet.lang.types.*;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -89,8 +92,18 @@ public class DescriptorRenderer {
@Override @Override
public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) {
JetType outType = descriptor.getOutType(); String typeString = renderPropertyPrefixAndComputeTypeString(builder, Collections.<TypeParameterDescriptor>emptyList(), null, descriptor.getOutType(), descriptor.getInType());
JetType inType = descriptor.getInType(); renderName(descriptor, builder);
builder.append(" : ").append(escape(typeString));
return super.visitVariableDescriptor(descriptor, builder);
}
private String renderPropertyPrefixAndComputeTypeString(
@NotNull StringBuilder builder,
@NotNull List<TypeParameterDescriptor> typeParameters,
@Nullable JetType receiverType,
@Nullable JetType outType,
@Nullable JetType inType) {
String typeString = lt() + "no type>"; String typeString = lt() + "no type>";
if (inType != null && outType != null) { if (inType != null && outType != null) {
builder.append(renderKeyword("var")).append(" "); builder.append(renderKeyword("var")).append(" ");
@@ -109,9 +122,26 @@ public class DescriptorRenderer {
builder.append(lt()).append("write-only> "); builder.append(lt()).append("write-only> ");
typeString = inType.toString(); typeString = inType.toString();
} }
renderTypeParameters(typeParameters, builder);
if (receiverType != null) {
builder.append(escape(receiverType.toString())).append(".");
}
return typeString;
}
@Override
public Void visitPropertyDescriptor(PropertyDescriptor descriptor, StringBuilder builder) {
String typeString = renderPropertyPrefixAndComputeTypeString(
builder, descriptor.getTypeParemeters(),
descriptor.getReceiverType(),
descriptor.getOutType(),
descriptor.getInType());
renderName(descriptor, builder); renderName(descriptor, builder);
builder.append(" : ").append(escape(typeString)); builder.append(" : ").append(escape(typeString));
return super.visitVariableDescriptor(descriptor, builder); return null;
} }
@Override @Override
@@ -119,9 +149,6 @@ public class DescriptorRenderer {
builder.append(renderKeyword("fun")).append(" "); builder.append(renderKeyword("fun")).append(" ");
List<TypeParameterDescriptor> typeParameters = descriptor.getTypeParameters(); List<TypeParameterDescriptor> typeParameters = descriptor.getTypeParameters();
renderTypeParameters(typeParameters, builder); renderTypeParameters(typeParameters, builder);
if (!typeParameters.isEmpty()) {
builder.append(" ");
}
JetType receiverType = descriptor.getReceiverType(); JetType receiverType = descriptor.getReceiverType();
if (receiverType != null) { if (receiverType != null) {
@@ -151,7 +178,7 @@ public class DescriptorRenderer {
builder.append(", "); builder.append(", ");
} }
} }
builder.append(">"); builder.append("> ");
} }
} }