Declared vs inherited default values

A value parameter _declares _a default value when the value is explicitly provided in the declaration of the parameter.
A value parameter _has_ a default value when it declares a default value or an overridden function declares it for the same parameter
This commit is contained in:
Andrey Breslav
2012-04-27 19:30:40 +04:00
parent d3ceaf7656
commit 5453598b2f
5 changed files with 71 additions and 35 deletions
@@ -159,7 +159,7 @@ public class FunctionCodegen {
JetValueParameterAnnotationWriter av = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i + start); JetValueParameterAnnotationWriter av = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i + start);
ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i);
av.writeName(parameterDescriptor.getName()); av.writeName(parameterDescriptor.getName());
av.writeHasDefaultValue(parameterDescriptor.hasDefaultValue()); av.writeHasDefaultValue(parameterDescriptor.declaresDefaultValue());
av.writeNullable(parameterDescriptor.getType().isNullable()); av.writeNullable(parameterDescriptor.getType().isNullable());
if (jvmSignature.getKotlinParameterTypes() != null && jvmSignature.getKotlinParameterTypes().get(i) != null) { if (jvmSignature.getKotlinParameterTypes() != null && jvmSignature.getKotlinParameterTypes().get(i) != null) {
av.writeType(jvmSignature.getKotlinParameterTypes().get(i + start).getKotlinSignature()); av.writeType(jvmSignature.getKotlinParameterTypes().get(i + start).getKotlinSignature());
@@ -312,7 +312,7 @@ public class FunctionCodegen {
boolean needed = false; boolean needed = false;
if(functionDescriptor != null) { if(functionDescriptor != null) {
for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) {
if(parameterDescriptor.hasDefaultValue()) { if(parameterDescriptor.declaresDefaultValue()) {
needed = true; needed = true;
break; break;
} }
@@ -398,7 +398,7 @@ public class FunctionCodegen {
Type t = argumentTypes[extra + index]; Type t = argumentTypes[extra + index];
Label endArg = null; Label endArg = null;
if (parameterDescriptor.hasDefaultValue()) { if (parameterDescriptor.declaresDefaultValue()) {
iv.load(maskIndex, Type.INT_TYPE); iv.load(maskIndex, Type.INT_TYPE);
iv.iconst(1 << index); iv.iconst(1 << index);
iv.and(Type.INT_TYPE); iv.and(Type.INT_TYPE);
@@ -418,7 +418,7 @@ public class FunctionCodegen {
iv.load(var, t); iv.load(var, t);
var += t.getSize(); var += t.getSize();
if (parameterDescriptor.hasDefaultValue()) { if (parameterDescriptor.declaresDefaultValue()) {
iv.mark(endArg); iv.mark(endArg);
} }
} }
@@ -551,7 +551,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
for (ValueParameterDescriptor valueParameter : constructorDescriptor.getValueParameters()) { for (ValueParameterDescriptor valueParameter : constructorDescriptor.getValueParameters()) {
JetValueParameterAnnotationWriter jetValueParameterAnnotation = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i); JetValueParameterAnnotationWriter jetValueParameterAnnotation = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i);
jetValueParameterAnnotation.writeName(valueParameter.getName()); jetValueParameterAnnotation.writeName(valueParameter.getName());
jetValueParameterAnnotation.writeHasDefaultValue(valueParameter.hasDefaultValue()); jetValueParameterAnnotation.writeHasDefaultValue(valueParameter.declaresDefaultValue());
jetValueParameterAnnotation.writeType(constructorMethod.getKotlinParameterType(i)); jetValueParameterAnnotation.writeType(constructorMethod.getKotlinParameterType(i));
jetValueParameterAnnotation.visitEnd(); jetValueParameterAnnotation.visitEnd();
++i; ++i;
@@ -33,7 +33,22 @@ public interface ValueParameterDescriptor extends VariableDescriptor, Annotated
* @return the parameter index * @return the parameter index
*/ */
int getIndex(); int getIndex();
/**
* The font-end relies on this property when resolving function calls
*
* @return {@code true} iff the parameter has a default value, i.e. declares it or inherits
* by overriding a parameter in an overridden function.
*/
boolean hasDefaultValue(); boolean hasDefaultValue();
/**
* The back-end should relies on this property when generating function signatures
*
* @return {@code true} iff the parameter declares a default value, i.e. explicitly specifies it in the function header
*/
boolean declaresDefaultValue();
boolean isRef(); boolean isRef();
@Nullable JetType getVarargElementType(); @Nullable JetType getVarargElementType();
@@ -24,6 +24,7 @@ import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor; import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -31,12 +32,17 @@ import java.util.Set;
* @author abreslav * @author abreslav
*/ */
public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor { public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor {
private final boolean hasDefaultValue; private Boolean hasDefaultValue;
private final boolean declaresDefaultValue;
private final JetType varargElementType; private final JetType varargElementType;
private final boolean isVar; private final boolean isVar;
private final int index; private final int index;
private final ValueParameterDescriptor original; private final ValueParameterDescriptor original;
private final Set<ValueParameterDescriptor> overriddenDescriptors = Sets.newLinkedHashSet(); // Linked is essential private final Set<ValueParameterDescriptor> overriddenDescriptors = Sets.newLinkedHashSet(); // Linked is essential
private boolean overriddenDescriptorsLocked = false;
private final Set<? extends ValueParameterDescriptor> readOnlyOverriddenDescriptors = Collections.unmodifiableSet(overriddenDescriptors);
public ValueParameterDescriptorImpl( public ValueParameterDescriptorImpl(
@NotNull DeclarationDescriptor containingDeclaration, @NotNull DeclarationDescriptor containingDeclaration,
@@ -45,12 +51,12 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull String name, @NotNull String name,
boolean isVar, boolean isVar,
@NotNull JetType outType, @NotNull JetType outType,
boolean hasDefaultValue, boolean declaresDefaultValue,
@Nullable JetType varargElementType) { @Nullable JetType varargElementType) {
super(containingDeclaration, annotations, name, outType); super(containingDeclaration, annotations, name, outType);
this.original = this; this.original = this;
this.index = index; this.index = index;
this.hasDefaultValue = hasDefaultValue; this.declaresDefaultValue = declaresDefaultValue;
this.varargElementType = varargElementType; this.varargElementType = varargElementType;
this.isVar = isVar; this.isVar = isVar;
} }
@@ -66,7 +72,7 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
super(containingDeclaration, annotations, original.getName(), outType); super(containingDeclaration, annotations, original.getName(), outType);
this.original = original; this.original = original;
this.index = original.getIndex(); this.index = original.getIndex();
this.hasDefaultValue = original.hasDefaultValue(); this.declaresDefaultValue = original.declaresDefaultValue();
this.varargElementType = varargElementType; this.varargElementType = varargElementType;
this.isVar = isVar; this.isVar = isVar;
} }
@@ -83,9 +89,32 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@Override @Override
public boolean hasDefaultValue() { public boolean hasDefaultValue() {
computeDefaultValuePresence();
return hasDefaultValue; return hasDefaultValue;
} }
@Override
public boolean declaresDefaultValue() {
return declaresDefaultValue && ((CallableMemberDescriptor) getContainingDeclaration()).getKind().isReal();
}
private void computeDefaultValuePresence() {
if (hasDefaultValue != null) return;
overriddenDescriptorsLocked = true;
if (declaresDefaultValue) {
hasDefaultValue = true;
}
else {
for (ValueParameterDescriptor descriptor : overriddenDescriptors) {
if (descriptor.hasDefaultValue()) {
hasDefaultValue = true;
return;
}
}
hasDefaultValue = false;
}
}
@Override @Override
public boolean isRef() { public boolean isRef() {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
@@ -138,11 +167,13 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull @NotNull
@Override @Override
public Set<? extends ValueParameterDescriptor> getOverriddenDescriptors() { public Set<? extends ValueParameterDescriptor> getOverriddenDescriptors() {
return overriddenDescriptors; return readOnlyOverriddenDescriptors;
} }
@Override @Override
public void addOverriddenDescriptor(@NotNull ValueParameterDescriptor overridden) { public void addOverriddenDescriptor(@NotNull ValueParameterDescriptor overridden) {
assert !overriddenDescriptorsLocked : "Adding more overridden descriptors is not allowed at this point: " +
"the presence of the default value has already been calculated";
overriddenDescriptors.add(overridden); overriddenDescriptors.add(overridden);
} }
} }
@@ -83,18 +83,7 @@ public class OverrideResolver {
checkVisibility(); checkVisibility();
checkOverrides(invisibleOverriddenDescriptors); checkOverrides(invisibleOverriddenDescriptors);
checkParameterOverrides(); checkParameterOverridesForAllClasses();
}
private void checkParameterOverrides() {
List<MutableClassDescriptor> allClasses = Lists.newArrayList(context.getClasses().values());
allClasses.addAll(context.getObjects().values());
for (MutableClassDescriptor classDescriptor : allClasses) {
Collection<CallableMemberDescriptor> members = classDescriptor.getAllCallableMembers();
for (CallableMemberDescriptor member : members) {
checkOverridesForParameters(member);
}
}
} }
/** /**
@@ -416,6 +405,17 @@ public class OverrideResolver {
} }
} }
private void checkParameterOverridesForAllClasses() {
List<MutableClassDescriptor> allClasses = Lists.newArrayList(context.getClasses().values());
allClasses.addAll(context.getObjects().values());
for (MutableClassDescriptor classDescriptor : allClasses) {
Collection<CallableMemberDescriptor> members = classDescriptor.getAllCallableMembers();
for (CallableMemberDescriptor member : members) {
checkOverridesForParameters(member);
}
}
}
private void checkOverridesForParameters(CallableMemberDescriptor declared) { private void checkOverridesForParameters(CallableMemberDescriptor declared) {
boolean fakeOverride = declared.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE; boolean fakeOverride = declared.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
if (!fakeOverride) { if (!fakeOverride) {
@@ -437,23 +437,13 @@ public class OverrideResolver {
fakeOverride ? null : fakeOverride ? null :
(JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass); (JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass);
if (parameterFromSubclass.hasDefaultValue() && !fakeOverride) { if (parameterFromSubclass.declaresDefaultValue() && !fakeOverride) {
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter)); trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter));
} }
// If p1 overrides p2 and p3 and p2 overrides p3, we remove p2 from p1's overridden list
Set<ValueParameterDescriptor> uniqueOverridden = Sets.newHashSet(parameterFromSubclass.getOverriddenDescriptors());
for (ValueParameterDescriptor p2 : parameterFromSubclass.getOverriddenDescriptors()) {
for (ValueParameterDescriptor p3 : p2.getOverriddenDescriptors()) {
if (uniqueOverridden.contains(p3)) {
uniqueOverridden.remove(p2);
}
}
}
boolean superWithDefault = false; boolean superWithDefault = false;
for (ValueParameterDescriptor parameterFromSuperclass : uniqueOverridden) { for (ValueParameterDescriptor parameterFromSuperclass : parameterFromSubclass.getOverriddenDescriptors()) {
if (parameterFromSuperclass.hasDefaultValue()) { if (parameterFromSuperclass.declaresDefaultValue()) {
if (!superWithDefault) { if (!superWithDefault) {
superWithDefault = true; superWithDefault = true;
} }