diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java index a35861150dd..aa44904f02f 100644 --- a/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java +++ b/idea/src/org/jetbrains/jet/lang/descriptors/PropertyDescriptor.java @@ -1,5 +1,6 @@ package org.jetbrains.jet.lang.descriptors; +import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.types.JetType; @@ -15,6 +16,8 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member private final MemberModifiers memberModifiers; private final boolean isVar; + private final JetType receiverType; + private final List typeParemeters = Lists.newArrayListWithCapacity(0); private PropertyGetterDescriptor getter; private PropertySetterDescriptor setter; @@ -23,35 +26,51 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member @NotNull List annotations, @NotNull MemberModifiers memberModifiers, boolean isVar, + @Nullable JetType receiverType, @NotNull String name, @Nullable JetType inType, - @Nullable JetType outType) { + @NotNull JetType outType) { super(containingDeclaration, annotations, name, inType, outType); assert !isVar || inType != null; - assert outType != null; +// assert outType != null; this.isVar = isVar; this.memberModifiers = memberModifiers; + this.receiverType = receiverType; } - public PropertyDescriptor( + private PropertyDescriptor( @NotNull PropertyDescriptor original, + @Nullable JetType receiverType, @Nullable JetType inType, - @Nullable JetType outType) { + @NotNull JetType outType) { this( original.getContainingDeclaration(), original.getAnnotations(), // TODO : substitute? original.getModifiers(), original.isVar, + receiverType, original.getName(), inType, outType); } - public void initialize(@Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) { + public void initialize(@NotNull List typeParameters, @Nullable PropertyGetterDescriptor getter, @Nullable PropertySetterDescriptor setter) { + this.typeParemeters.addAll(typeParameters); this.getter = getter; this.setter = setter; } + @NotNull + public List getTypeParemeters() { + return typeParemeters; + } + + @Nullable + public JetType getReceiverType() { + return receiverType; + } + + public boolean isVar() { return isVar; } @@ -78,12 +97,14 @@ public class PropertyDescriptor extends VariableDescriptorImpl implements Member JetType originalInType = getInType(); JetType inType = originalInType == null ? null : substitutor.substitute(originalInType, Variance.IN_VARIANCE); 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) { return null; // TODO : tell the user that the property was projected out } + JetType receiverType = getReceiverType(); return new PropertyDescriptor( this, + receiverType == null ? null : substitutor.substitute(receiverType, Variance.IN_VARIANCE), inType, outType ); diff --git a/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java b/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java index 1832238692f..5882e24fde0 100644 --- a/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java +++ b/idea/src/org/jetbrains/jet/lang/psi/JetProperty.java @@ -14,7 +14,7 @@ import java.util.List; /** * @author max */ -public class JetProperty extends JetNamedDeclaration { +public class JetProperty extends JetTypeParameterListOwner { public JetProperty(@NotNull ASTNode node) { super(node); } @@ -44,7 +44,6 @@ public class JetProperty extends JetNamedDeclaration { return null; } - @Nullable public JetTypeReference getPropertyTypeRef() { ASTNode node = getNode().getFirstChildNode(); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index 2aa84367b4a..a66cfa3bbb2 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -358,22 +358,45 @@ public class ClassDescriptorResolver { @NotNull public PropertyDescriptor resolvePropertyDescriptor(@NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope scope, JetProperty property) { - JetType type = getType(scope, property, true); - boolean isVar = property.isVar(); + JetScope scopeWithTypeParameters; + List typeParameterDescriptors; + List 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(); + boolean isVar = property.isVar(); + + JetType type = getType(scopeWithTypeParameters, property, true); + PropertyDescriptor propertyDescriptor = new PropertyDescriptor( containingDeclaration, AnnotationResolver.INSTANCE.resolveAnnotations(modifierList), resolveModifiers(modifierList, DEFAULT_MODIFIERS), // TODO : default modifiers differ in different contexts isVar, + receiverType, JetPsiUtil.safeName(property.getName()), isVar ? type : null, type); propertyDescriptor.initialize( - resolvePropertyGetterDescriptor(scope, property, propertyDescriptor), - resolvePropertySetterDescriptor(scope, property, propertyDescriptor)); + typeParameterDescriptors, + resolvePropertyGetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor), + resolvePropertySetterDescriptor(scopeWithTypeParameters, property, propertyDescriptor)); trace.recordDeclarationResolution(property, propertyDescriptor); return propertyDescriptor; @@ -384,14 +407,12 @@ public class ClassDescriptorResolver { // TODO : receiver? JetTypeReference propertyTypeRef = property.getPropertyTypeRef(); - JetType type; if (propertyTypeRef == null) { final JetExpression initializer = property.getInitializer(); if (initializer == null) { 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 { - // TODO : ??? Fix-point here: what if we have something like "val a = foo {a.bar()}" // TODO : a risk of a memory leak LazyValue lazyValue = new LazyValue() { @Override @@ -400,16 +421,15 @@ public class ClassDescriptorResolver { } }; if (allowDeferred) { - type = new DeferredType(lazyValue); + return new DeferredType(lazyValue); } else { - type = lazyValue.get(); + return lazyValue.get(); } } } else { - type = typeResolver.resolveType(scope, propertyTypeRef); + return typeResolver.resolveType(scope, propertyTypeRef); } - return type; } @NotNull @@ -551,10 +571,11 @@ public class ClassDescriptorResolver { AnnotationResolver.INSTANCE.resolveAnnotations(modifierList), resolveModifiers(modifierList, DEFAULT_MODIFIERS), isMutable, + null, name == null ? "" : name, isMutable ? type : null, type); - propertyDescriptor.initialize(null, null); + propertyDescriptor.initialize(Collections.emptyList(), null, null); trace.recordValueParameterAsPropertyResolution(parameter, propertyDescriptor); return propertyDescriptor; } diff --git a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java index 1cd1cdeb39a..af73e5d911c 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/java/JavaClassMembersScope.java @@ -92,6 +92,7 @@ public class JavaClassMembersScope implements JetScope { Collections.emptyList(), new MemberModifiers(false, false, false), !isFinal, + null, field.getName(), isFinal ? null : type, type); diff --git a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java index ce44f92e1fe..c17a9950a81 100644 --- a/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java +++ b/idea/src/org/jetbrains/jet/lang/types/ErrorUtils.java @@ -100,7 +100,13 @@ public class ErrorUtils { private static final JetType ERROR_PROPERTY_TYPE = createErrorType(""); private static final VariableDescriptor ERROR_PROPERTY = new PropertyDescriptor( - ERROR_CLASS, Collections.emptyList(), new MemberModifiers(false, false, false), true, "", ERROR_PROPERTY_TYPE, ERROR_PROPERTY_TYPE); + ERROR_CLASS, + Collections.emptyList(), + new MemberModifiers(false, false, false), + true, + null, + "", + ERROR_PROPERTY_TYPE, ERROR_PROPERTY_TYPE); private static FunctionDescriptor createErrorFunction(List typeParameters, List positionedValueArgumentTypes) { FunctionDescriptorImpl functionDescriptor = new FunctionDescriptorImpl(ERROR_CLASS, Collections.emptyList(), ""); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index 24b54f28238..2e830f0600d 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -883,8 +883,6 @@ public class JetTypeInferrer { } } - - @Override public void visitTupleExpression(JetTupleExpression expression) { List entries = expression.getEntries(); @@ -1019,7 +1017,10 @@ public class JetTypeInferrer { @Override public void visitWhenConditionIsPattern(JetWhenConditionIsPattern condition) { - checkPatternType(condition.getPattern(), finalSubjectType); + JetPattern pattern = condition.getPattern(); + if (pattern != null) { + checkPatternType(pattern, finalSubjectType); + } } @Override diff --git a/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java b/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java index f0db290804a..88fd9e9ba65 100644 --- a/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java +++ b/idea/src/org/jetbrains/jet/resolve/DescriptorRenderer.java @@ -1,9 +1,12 @@ 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.types.*; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -89,8 +92,18 @@ public class DescriptorRenderer { @Override public Void visitVariableDescriptor(VariableDescriptor descriptor, StringBuilder builder) { - JetType outType = descriptor.getOutType(); - JetType inType = descriptor.getInType(); + String typeString = renderPropertyPrefixAndComputeTypeString(builder, Collections.emptyList(), null, descriptor.getOutType(), descriptor.getInType()); + renderName(descriptor, builder); + builder.append(" : ").append(escape(typeString)); + return super.visitVariableDescriptor(descriptor, builder); + } + + private String renderPropertyPrefixAndComputeTypeString( + @NotNull StringBuilder builder, + @NotNull List typeParameters, + @Nullable JetType receiverType, + @Nullable JetType outType, + @Nullable JetType inType) { String typeString = lt() + "no type>"; if (inType != null && outType != null) { builder.append(renderKeyword("var")).append(" "); @@ -109,9 +122,26 @@ public class DescriptorRenderer { builder.append(lt()).append("write-only> "); 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); builder.append(" : ").append(escape(typeString)); - return super.visitVariableDescriptor(descriptor, builder); + return null; } @Override @@ -119,9 +149,6 @@ public class DescriptorRenderer { builder.append(renderKeyword("fun")).append(" "); List typeParameters = descriptor.getTypeParameters(); renderTypeParameters(typeParameters, builder); - if (!typeParameters.isEmpty()) { - builder.append(" "); - } JetType receiverType = descriptor.getReceiverType(); if (receiverType != null) { @@ -151,7 +178,7 @@ public class DescriptorRenderer { builder.append(", "); } } - builder.append(">"); + builder.append("> "); } }