Checks for default parameter value consistency

Inheriting default values from multiple superclasses is prohibited
This commit is contained in:
Andrey Breslav
2012-04-26 17:32:37 +04:00
parent 07c5f8e12a
commit 058e4b833b
10 changed files with 138 additions and 9 deletions
@@ -36,7 +36,7 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
private final boolean isVar;
private final int index;
private final ValueParameterDescriptor original;
private final Set<ValueParameterDescriptor> overriddenDescriptors = Sets.newHashSet();
private final Set<ValueParameterDescriptor> overriddenDescriptors = Sets.newLinkedHashSet(); // Linked is essential
public ValueParameterDescriptorImpl(
@NotNull DeclarationDescriptor containingDeclaration,
@@ -381,6 +381,8 @@ public interface Errors {
DiagnosticFactory2.create(ERROR);
SimpleDiagnosticFactory<JetParameter> DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = SimpleDiagnosticFactory.create(ERROR, PositioningStrategies.PARAMETER_DEFAULT_VALUE);
DiagnosticFactory1<JetParameter, ValueParameterDescriptor> MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES = DiagnosticFactory1.create(ERROR, PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory1<JetClassOrObject, ValueParameterDescriptor> MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE = DiagnosticFactory1.create(ERROR, PositioningStrategies.POSITION_NAME_IDENTIFIER);
DiagnosticFactory2<JetDeclaration, CallableMemberDescriptor, String> CONFLICTING_OVERLOADS =
DiagnosticFactory2.create(ERROR, new PositioningStrategy<JetDeclaration>() {
@@ -386,6 +386,11 @@ public class DefaultErrorMessages {
MAP.put(NOT_AN_ANNOTATION_CLASS, "''{0}'' is not an annotation class", TO_STRING);
MAP.put(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE, "An overriding function is not allowed to specify default values for its parameters");
MAP.put(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES, "More than one overridden descriptor declares a default value for ''{0}''. " +
"As the compiler can not make sure these values agree, this is not allowed.", TO_STRING);
MAP.put(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE, "More than one overridden descriptor declares a default value for ''{0}''. " +
"As the compiler can not make sure these values agree, this is not allowed.", TO_STRING);
MAP.setImmutable();
}
@@ -17,6 +17,7 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -25,7 +26,7 @@ import java.util.List;
/**
* @author max
*/
public interface JetClassOrObject extends PsiElement {
public interface JetClassOrObject extends PsiElement, PsiNameIdentifierOwner {
List<JetDeclaration> getDeclarations();
@Nullable
@@ -16,7 +16,10 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.*;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.LinkedMultiMap;
@@ -80,6 +83,20 @@ public class OverrideResolver {
checkVisibility();
checkOverrides(invisibleOverriddenDescriptors);
checkParameterOverrides();
}
private void checkParameterOverrides() {
List<MutableClassDescriptor> allClasses = Lists.newArrayList(context.getClasses().values());
allClasses.addAll(context.getObjects().values());
for (MutableClassDescriptor classDescriptor : allClasses) {
Collection<CallableMemberDescriptor> members = classDescriptor.getCallableMembers();
for (CallableMemberDescriptor member : members) {
//if (member.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) {
checkOverridesForParameters(member);
//}
}
}
}
/**
@@ -394,10 +411,6 @@ public class OverrideResolver {
}
}
if (hasOverrideModifier) {
checkOverridesForParameters(declared);
}
if (hasOverrideModifier && declared.getOverriddenDescriptors().size() == 0) {
if (!invisibleOverriddenDescriptors.get(declared).isEmpty()) {
CallableDescriptor descriptor = invisibleOverriddenDescriptors.values().iterator().next();
@@ -415,6 +428,16 @@ public class OverrideResolver {
}
private void checkOverridesForParameters(CallableMemberDescriptor declared) {
boolean fakeOverride = declared.getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE;
if (!fakeOverride) {
// No check if the function is not marked as 'override'
JetModifierListOwner declaration =
(JetModifierListOwner) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), declared);
if (!declaration.hasModifier(JetTokens.OVERRIDE_KEYWORD)) {
return;
}
}
// Let p1 be a parameter of the overriding function
// Let p2 be a parameter of the function being overridden
// Then
@@ -422,10 +445,42 @@ public class OverrideResolver {
// b) p1 must have the same name as p2
for (ValueParameterDescriptor parameterFromSubclass : declared.getValueParameters()) {
JetParameter parameter =
(JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass);
if (parameterFromSubclass.hasDefaultValue()) {
fakeOverride ? null :
(JetParameter) BindingContextUtils.descriptorToDeclaration(trace.getBindingContext(), parameterFromSubclass);
if (parameterFromSubclass.hasDefaultValue() && !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<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;
for (ValueParameterDescriptor parameterFromSuperclass : uniqueOverridden) {
if (parameterFromSuperclass.hasDefaultValue()) {
if (!superWithDefault) {
superWithDefault = true;
}
else {
if (fakeOverride) {
JetClassOrObject classElement = (JetClassOrObject) BindingContextUtils
.descriptorToDeclaration(trace.getBindingContext(), declared.getContainingDeclaration());
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, parameterFromSubclass));
}
else {
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES.on(parameter, parameterFromSubclass));
}
break;
}
}
}
}
}
@@ -0,0 +1,15 @@
trait Y {
fun foo(a : Int = 1)
}
trait YSub : Y {
}
class Z2 : Y, YSub {
override fun foo(a : Int) {}
}
class Z2O : Y, YSub {
override fun foo(a : Int) {}
}
@@ -0,0 +1,15 @@
trait X {
fun foo(a : Int = 1)
}
trait Y {
fun foo(a : Int = 1)
}
class Z : X, Y {
override fun foo(<!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES!>a<!> : Int) {}
}
object ZO : X, Y {
override fun foo(<!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES!>a<!> : Int) {}
}
@@ -0,0 +1,15 @@
trait X {
fun foo(a : Int = 1)
}
trait Y {
fun foo(a : Int = 1)
}
class Z : X, Y {
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>(a : Int) {}
}
object ZO : X, Y {
fun <!VIRTUAL_MEMBER_HIDDEN!>foo<!>(a : Int) {}
}
@@ -0,0 +1,10 @@
trait X {
fun foo(a : Int = 1)
}
trait Y {
fun foo(a : Int = 1)
}
class <!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE!>Z1<!> : X, Y {} // BUG
object <!MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE!>Z1O<!> : X, Y {} // BUG
@@ -0,0 +1,11 @@
trait X {
fun foo(a : Int = 1)
}
trait Y {
fun foo(a : Int)
}
class Z : X, Y {
override fun foo(a : Int) {}
}