diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java index abc28ddd3d9..d759cf0e671 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java @@ -159,7 +159,7 @@ public class FunctionCodegen { JetValueParameterAnnotationWriter av = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i + start); ValueParameterDescriptor parameterDescriptor = paramDescrs.get(i); av.writeName(parameterDescriptor.getName()); - av.writeHasDefaultValue(parameterDescriptor.hasDefaultValue()); + av.writeHasDefaultValue(parameterDescriptor.declaresDefaultValue()); av.writeNullable(parameterDescriptor.getType().isNullable()); if (jvmSignature.getKotlinParameterTypes() != null && jvmSignature.getKotlinParameterTypes().get(i) != null) { av.writeType(jvmSignature.getKotlinParameterTypes().get(i + start).getKotlinSignature()); @@ -312,7 +312,7 @@ public class FunctionCodegen { boolean needed = false; if(functionDescriptor != null) { for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { - if(parameterDescriptor.hasDefaultValue()) { + if(parameterDescriptor.declaresDefaultValue()) { needed = true; break; } @@ -398,7 +398,7 @@ public class FunctionCodegen { Type t = argumentTypes[extra + index]; Label endArg = null; - if (parameterDescriptor.hasDefaultValue()) { + if (parameterDescriptor.declaresDefaultValue()) { iv.load(maskIndex, Type.INT_TYPE); iv.iconst(1 << index); iv.and(Type.INT_TYPE); @@ -418,7 +418,7 @@ public class FunctionCodegen { iv.load(var, t); var += t.getSize(); - if (parameterDescriptor.hasDefaultValue()) { + if (parameterDescriptor.declaresDefaultValue()) { iv.mark(endArg); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java index 187277785a0..c9475688601 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java @@ -551,7 +551,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen { for (ValueParameterDescriptor valueParameter : constructorDescriptor.getValueParameters()) { JetValueParameterAnnotationWriter jetValueParameterAnnotation = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i); jetValueParameterAnnotation.writeName(valueParameter.getName()); - jetValueParameterAnnotation.writeHasDefaultValue(valueParameter.hasDefaultValue()); + jetValueParameterAnnotation.writeHasDefaultValue(valueParameter.declaresDefaultValue()); jetValueParameterAnnotation.writeType(constructorMethod.getKotlinParameterType(i)); jetValueParameterAnnotation.visitEnd(); ++i; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java index 4893e9f4598..c8482b6f233 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptor.java @@ -33,7 +33,22 @@ public interface ValueParameterDescriptor extends VariableDescriptor, Annotated * @return the parameter index */ 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(); + + /** + * 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(); @Nullable JetType getVarargElementType(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java index 766b544c73c..fd948e8a0fc 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/ValueParameterDescriptorImpl.java @@ -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.TypeSubstitutor; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -31,12 +32,17 @@ import java.util.Set; * @author abreslav */ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl implements MutableValueParameterDescriptor { - private final boolean hasDefaultValue; + private Boolean hasDefaultValue; + private final boolean declaresDefaultValue; + private final JetType varargElementType; private final boolean isVar; private final int index; private final ValueParameterDescriptor original; + private final Set overriddenDescriptors = Sets.newLinkedHashSet(); // Linked is essential + private boolean overriddenDescriptorsLocked = false; + private final Set readOnlyOverriddenDescriptors = Collections.unmodifiableSet(overriddenDescriptors); public ValueParameterDescriptorImpl( @NotNull DeclarationDescriptor containingDeclaration, @@ -45,12 +51,12 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @NotNull String name, boolean isVar, @NotNull JetType outType, - boolean hasDefaultValue, + boolean declaresDefaultValue, @Nullable JetType varargElementType) { super(containingDeclaration, annotations, name, outType); this.original = this; this.index = index; - this.hasDefaultValue = hasDefaultValue; + this.declaresDefaultValue = declaresDefaultValue; this.varargElementType = varargElementType; this.isVar = isVar; } @@ -66,7 +72,7 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme super(containingDeclaration, annotations, original.getName(), outType); this.original = original; this.index = original.getIndex(); - this.hasDefaultValue = original.hasDefaultValue(); + this.declaresDefaultValue = original.declaresDefaultValue(); this.varargElementType = varargElementType; this.isVar = isVar; } @@ -83,9 +89,32 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @Override public boolean hasDefaultValue() { + computeDefaultValuePresence(); 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 public boolean isRef() { throw new UnsupportedOperationException(); // TODO @@ -138,11 +167,13 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme @NotNull @Override public Set getOverriddenDescriptors() { - return overriddenDescriptors; + return readOnlyOverriddenDescriptors; } @Override 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); } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java index b8f1dadd699..9665b4c5292 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -83,18 +83,7 @@ public class OverrideResolver { checkVisibility(); checkOverrides(invisibleOverriddenDescriptors); - checkParameterOverrides(); - } - - private void checkParameterOverrides() { - List allClasses = Lists.newArrayList(context.getClasses().values()); - allClasses.addAll(context.getObjects().values()); - for (MutableClassDescriptor classDescriptor : allClasses) { - Collection members = classDescriptor.getAllCallableMembers(); - for (CallableMemberDescriptor member : members) { - checkOverridesForParameters(member); - } - } + checkParameterOverridesForAllClasses(); } /** @@ -416,6 +405,17 @@ public class OverrideResolver { } } + private void checkParameterOverridesForAllClasses() { + List allClasses = Lists.newArrayList(context.getClasses().values()); + allClasses.addAll(context.getObjects().values()); + for (MutableClassDescriptor classDescriptor : allClasses) { + Collection members = classDescriptor.getAllCallableMembers(); + for (CallableMemberDescriptor member : members) { + checkOverridesForParameters(member); + } + } + } + private void checkOverridesForParameters(CallableMemberDescriptor declared) { boolean fakeOverride = declared.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE; if (!fakeOverride) { @@ -437,23 +437,13 @@ public class OverrideResolver { fakeOverride ? null : (JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass); - if (parameterFromSubclass.hasDefaultValue() && !fakeOverride) { + if (parameterFromSubclass.declaresDefaultValue() && !fakeOverride) { 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 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; - for (ValueParameterDescriptor parameterFromSuperclass : uniqueOverridden) { - if (parameterFromSuperclass.hasDefaultValue()) { + for (ValueParameterDescriptor parameterFromSuperclass : parameterFromSubclass.getOverriddenDescriptors()) { + if (parameterFromSuperclass.declaresDefaultValue()) { if (!superWithDefault) { superWithDefault = true; }