From afad00fac532357deea161d2149209f26e6cf747 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Tue, 27 Sep 2011 12:32:14 +0400 Subject: [PATCH] Overriding var by val prohibited --- .../jet/lang/diagnostics/Errors.java | 1 + .../jetbrains/jet/lang/psi/JetProperty.java | 15 ++++++- .../jet/lang/resolve/OverrideResolver.java | 42 +++++++++++++++++-- .../quick/OverridingVarByVal.jet | 11 +++++ 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 idea/testData/checkerWithErrorTypes/quick/OverridingVarByVal.jet diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index a834d74feee..6f52f0882ce 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -316,6 +316,7 @@ public interface Errors { } }; + ParameterizedDiagnosticFactory2 VAR_OVERRIDDEN_BY_VAL = new ParameterizedDiagnosticFactory2(ERROR, "Var-property {0} cannot be overridden by val-property {1}", DescriptorRenderer.TEXT); ParameterizedDiagnosticFactory2 ABSTRACT_MEMBER_NOT_IMPLEMENTED = new ParameterizedDiagnosticFactory2(ERROR, "Class ''{0}'' must be declared abstract or implement abstract member {1}") { @Override diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java index 679b6a2adb1..6e5b0f476ec 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetProperty.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.tree.IElementType; +import com.intellij.psi.tree.TokenSet; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -11,6 +12,11 @@ import org.jetbrains.jet.lexer.JetTokens; import java.util.List; +import static org.jetbrains.jet.JetNodeTypes.PROPERTY_ACCESSOR; +import static org.jetbrains.jet.lexer.JetTokens.EQ; +import static org.jetbrains.jet.lexer.JetTokens.VAL_KEYWORD; +import static org.jetbrains.jet.lexer.JetTokens.VAR_KEYWORD; + /** * @author max */ @@ -69,7 +75,7 @@ public class JetProperty extends JetTypeParameterListOwner implements JetModifie @NotNull public List getAccessors() { - return findChildrenByType(JetNodeTypes.PROPERTY_ACCESSOR); + return findChildrenByType(PROPERTY_ACCESSOR); } @Nullable @@ -92,7 +98,12 @@ public class JetProperty extends JetTypeParameterListOwner implements JetModifie @Nullable public JetExpression getInitializer() { - PsiElement eq = findChildByType(JetTokens.EQ); + PsiElement eq = findChildByType(EQ); return PsiTreeUtil.getNextSiblingOfType(eq, JetExpression.class); } + + @NotNull + public ASTNode getValOrVarNode() { + return getNode().findChildByType(TokenSet.create(VAL_KEYWORD, VAR_KEYWORD)); + } } 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 97af644f0b3..a59a66ac7ff 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -1,7 +1,6 @@ package org.jetbrains.jet.lang.resolve; -import com.google.common.collect.Multimap; -import com.google.common.collect.Sets; +import com.google.common.collect.*; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; @@ -105,12 +104,28 @@ public class OverrideResolver { // Check if everything that must be overridden, actually is // Everything from supertypes + Set delegatedByExpression = Sets.newHashSet(); + for (JetDelegationSpecifier delegationSpecifier : klass.getDelegationSpecifiers()) { + if (delegationSpecifier instanceof JetDelegatorByExpressionSpecifier) { + JetDelegatorByExpressionSpecifier specifier = (JetDelegatorByExpressionSpecifier) delegationSpecifier; + JetType type = context.getTrace().get(BindingContext.TYPE, specifier.getTypeReference()); + if (type != null) { + delegatedByExpression.add(type); + } + } + } + + Map implementedWithDelegationBy = Maps.newHashMap(); Set inheritedFunctions = Sets.newLinkedHashSet(); for (JetType supertype : classDescriptor.getSupertypes()) { + boolean delegatedBy = delegatedByExpression.contains(supertype); for (DeclarationDescriptor descriptor : supertype.getMemberScope().getAllDescriptors()) { if (descriptor instanceof CallableMemberDescriptor) { CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor; inheritedFunctions.add(memberDescriptor); + if (delegatedBy && memberDescriptor.getModality().isOpen()) { + implementedWithDelegationBy.put(memberDescriptor, createOverridingDescriptor(classDescriptor, memberDescriptor)); + } } } } @@ -123,7 +138,7 @@ public class OverrideResolver { for (CallableMemberDescriptor one : filteredMembers) { if (factoredMembers.values().contains(one)) continue; for (CallableMemberDescriptor another : filteredMembers) { - if (one == another) continue; +// if (one == another) continue; factoredMembers.put(one, one); if (OverridingUtil.isOverridableBy(one, another).isSuccess() || OverridingUtil.isOverridableBy(another, one).isSuccess()) { @@ -154,7 +169,7 @@ public class OverrideResolver { } // Members actually present (declared) in the class - Set actuallyOverridden = Sets.newHashSet(); + Set actuallyOverridden = Sets.newHashSet(implementedWithDelegationBy.keySet()); for (CallableMemberDescriptor member : classDescriptor.getCallableMembers()) { actuallyOverridden.addAll(member.getOverriddenDescriptors()); } @@ -215,6 +230,11 @@ public class OverrideResolver { // } } + @Nullable + private CallableMemberDescriptor createOverridingDescriptor(@NotNull MutableClassDescriptor subClass, @NotNull CallableMemberDescriptor superDescriptor) { + return null; + } + private void checkOverride(CallableMemberDescriptor declared) { JetNamedDeclaration member = (JetNamedDeclaration) context.getTrace().get(BindingContext.DESCRIPTOR_TO_DECLARATION, declared); assert member != null; @@ -224,6 +244,7 @@ public class OverrideResolver { boolean finalOverriddenError = false; boolean typeMismatchError = false; + boolean kindMismatchError = false; for (CallableMemberDescriptor overridden : declared.getOverriddenDescriptors()) { if (overridden != null) { if (hasOverrideModifier) { @@ -237,6 +258,11 @@ public class OverrideResolver { context.getTrace().report(RETURN_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)); typeMismatchError = true; } + + if (checkPropertyKind(overridden, true) && checkPropertyKind(declared, false) && !kindMismatchError) { + context.getTrace().report(VAR_OVERRIDDEN_BY_VAL.on(member, ((JetProperty) member).getValOrVarNode(), (PropertyDescriptor) declared, (PropertyDescriptor) overridden)); + typeMismatchError = true; + } } } } @@ -253,4 +279,12 @@ public class OverrideResolver { context.getTrace().report(VIRTUAL_MEMBER_HIDDEN.on(member, nameIdentifier, declared, overridden, overridden.getContainingDeclaration())); } } + + private boolean checkPropertyKind(CallableMemberDescriptor descriptor, boolean isVar) { + if (descriptor instanceof PropertyDescriptor) { + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + return propertyDescriptor.isVar() == isVar; + } + return false; + } } diff --git a/idea/testData/checkerWithErrorTypes/quick/OverridingVarByVal.jet b/idea/testData/checkerWithErrorTypes/quick/OverridingVarByVal.jet new file mode 100644 index 00000000000..d77e85744b9 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/OverridingVarByVal.jet @@ -0,0 +1,11 @@ +open class Var() { + open var v : Int = 1 +} + +class Val() : Var() { + override val v : Int = 1 +} + +class Var2() : Var() { + override var v : Int = 1 +}