KT-4198 On covariant projection, do not throw whole var's away

#KT-4198 Fixed
This commit is contained in:
Andrey Breslav
2013-11-16 19:38:45 +04:00
parent 3fe55c997f
commit 38b38e7b6d
11 changed files with 123 additions and 4 deletions
@@ -30,6 +30,16 @@ public interface PropertyDescriptor extends VariableDescriptor, CallableMemberDe
@Nullable
PropertySetterDescriptor getSetter();
/**
* In the following case, the setter is projected out:
*
* trait Tr<T> { var v: T }
* fun test(tr: Tr<out String>) {
* tr.v = null!! // the assignment is illegal, although a read would be fine
* }
*/
boolean isSetterProjectedOut();
@NotNull
List<PropertyAccessorDescriptor> getAccessors();
@@ -30,6 +30,7 @@ import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import java.util.Collections;
import java.util.List;
@@ -49,6 +50,7 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
private List<TypeParameterDescriptor> typeParameters;
private PropertyGetterDescriptorImpl getter;
private PropertySetterDescriptor setter;
private boolean setterProjectedOut;
private PropertyDescriptorImpl(
@Nullable PropertyDescriptor original,
@@ -125,6 +127,10 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
this.setter = setter;
}
public void setSetterProjectedOut(boolean setterProjectedOut) {
this.setterProjectedOut = setterProjectedOut;
}
public void setVisibility(@NotNull Visibility visibility) {
this.visibility = visibility;
}
@@ -182,6 +188,11 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
return setter;
}
@Override
public boolean isSetterProjectedOut() {
return setterProjectedOut;
}
@Override
@NotNull
public List<PropertyAccessorDescriptor> getAccessors() {
@@ -253,7 +264,15 @@ public class PropertyDescriptorImpl extends VariableDescriptorImpl implements Pr
if (newSetter != null) {
List<ValueParameterDescriptor> substitutedValueParameters = FunctionDescriptorImpl.getSubstitutedValueParameters(newSetter, setter, substitutor);
if (substitutedValueParameters == null) {
return null;
// The setter is projected out, e.g. in this case:
// trait Tr<T> { var v: T }
// fun test(tr: Tr<out Any?>) { ... }
// we want to tell the user that although the property is declared as a var,
// it can not be assigned to because of the projection
substitutedDescriptor.setSetterProjectedOut(true);
substitutedValueParameters = Collections.<ValueParameterDescriptor>singletonList(
PropertySetterDescriptorImpl.createSetterParameter(newSetter, KotlinBuiltIns.getInstance().getNothingType())
);
}
if (substitutedValueParameters.size() != 1) {
throw new IllegalStateException();
@@ -67,7 +67,16 @@ public class PropertySetterDescriptorImpl extends PropertyAccessorDescriptorImpl
public void initializeDefault() {
assert parameter == null;
parameter = new ValueParameterDescriptorImpl(this, 0, Collections.<AnnotationDescriptor>emptyList(), Name.special("<set-?>"), getCorrespondingProperty().getReturnType(), false, null);
parameter = createSetterParameter(this, getCorrespondingProperty().getReturnType());
}
public static ValueParameterDescriptorImpl createSetterParameter(
@NotNull PropertySetterDescriptor setterDescriptor,
@NotNull JetType type
) {
return new ValueParameterDescriptorImpl(
setterDescriptor, 0, Collections.<AnnotationDescriptor>emptyList(), Name.special("<set-?>"), type, false, null
);
}
@NotNull