From e89a8c684f0e6025efed5052076300cd4ec9bcae Mon Sep 17 00:00:00 2001 From: Kirill Berezin Date: Wed, 19 Dec 2012 23:44:22 +0400 Subject: [PATCH] KT-3159 Disallow overriding var with different type #KT-3159 fixed --- .../jet/lang/diagnostics/Errors.java | 2 ++ .../rendering/DefaultErrorMessages.java | 3 +++ .../jet/lang/resolve/OverrideResolver.java | 21 ++++++++++++++++- .../jet/lang/resolve/OverridingUtil.java | 23 ++++++++++++++++--- .../diagnostics/tests/subtyping/kt3159.kt | 9 ++++++++ .../checkers/JetDiagnosticsTestGenerated.java | 5 ++++ .../plugin/highlighter/IdeErrorMessages.java | 14 ++++------- .../jet/plugin/highlighter/IdeRenderers.java | 14 +++++++---- 8 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/subtyping/kt3159.kt 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 13f3a2bfe14..d579f2f8795 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -221,6 +221,8 @@ public interface Errors { DiagnosticFactory3.create(ERROR, VISIBILITY_MODIFIER); DiagnosticFactory2 RETURN_TYPE_MISMATCH_ON_OVERRIDE = DiagnosticFactory2.create(ERROR, DECLARATION_RETURN_TYPE); + DiagnosticFactory2 PROPERTY_TYPE_MISMATCH_ON_OVERRIDE = + DiagnosticFactory2.create(ERROR, DECLARATION_RETURN_TYPE); DiagnosticFactory2 ABSTRACT_MEMBER_NOT_IMPLEMENTED = DiagnosticFactory2.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index 5c0b642daa2..e8f27095854 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -358,6 +358,9 @@ public class DefaultErrorMessages { MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, "Return type of ''{0}'' is not a subtype of the return type of overridden member {1}", NAME, DescriptorRenderer.TEXT); + MAP.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, "Type of ''{0}'' doesn't match to the type of overridden var-property {1}", + NAME, DescriptorRenderer.TEXT); + MAP.put(VAR_OVERRIDDEN_BY_VAL, "Var-property {0} cannot be overridden by val-property {1}", DescriptorRenderer.TEXT, DescriptorRenderer.TEXT); 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 97a39e3e61b..7ed17224518 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverrideResolver.java @@ -585,6 +585,8 @@ public class OverrideResolver { void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden); + void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden); + void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden); void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden); @@ -636,6 +638,14 @@ public class OverrideResolver { } } + @Override + public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + if (!typeMismatchError) { + typeMismatchError = true; + trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden)); + } + } + @Override public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) { if (!kindMismatchError) { @@ -674,7 +684,11 @@ public class OverrideResolver { reportError.overridingFinalMember(overridden); } - if (!OverridingUtil.isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, overridden, declared)) { + if (declared instanceof PropertyDescriptor && !OverridingUtil.isPropertyTypeOkForOverride( + JetTypeChecker.INSTANCE, (PropertyDescriptor) overridden, (PropertyDescriptor) declared)) { + reportError.propertyTypeMismatchOnOverride(overridden); + } + else if (!OverridingUtil.isReturnTypeOkForOverride(JetTypeChecker.INSTANCE, overridden, declared)) { reportError.returnTypeMismatchOnOverride(overridden); } @@ -721,6 +735,11 @@ public class OverrideResolver { } } + @Override + public void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden) { + throw new IllegalStateException("Component functions are not properties"); + } + @Override public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) { throw new IllegalStateException("Component functions are not properties"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java index 5d36440f8fd..e48e0104e34 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/OverridingUtil.java @@ -221,6 +221,21 @@ public class OverridingUtil { } public static boolean isReturnTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { + TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor); + + JetType superReturnType = superDescriptor.getReturnType(); + assert superReturnType != null; + + JetType subReturnType = subDescriptor.getReturnType(); + assert subReturnType != null; + + JetType substitutedSuperReturnType = typeSubstitutor.substitute(superReturnType, Variance.OUT_VARIANCE); + assert substitutedSuperReturnType != null; + + return typeChecker.isSubtypeOf(subReturnType, substitutedSuperReturnType); + } + + private static TypeSubstitutor prepareTypeSubstitutor(@NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) { List superTypeParameters = superDescriptor.getTypeParameters(); List subTypeParameters = subDescriptor.getTypeParameters(); Map substitutionContext = Maps.newHashMap(); @@ -231,12 +246,14 @@ public class OverridingUtil { superTypeParameter.getTypeConstructor(), new TypeProjection(subTypeParameter.getDefaultType())); } + return TypeSubstitutor.create(substitutionContext); + } - // This code compares return types, but they are not a part of the signature, so this code does not belong here - TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitutionContext); + public static boolean isPropertyTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull PropertyDescriptor superDescriptor, @NotNull PropertyDescriptor subDescriptor) { + TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor); JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE); assert substitutedSuperReturnType != null; - if (!typeChecker.isSubtypeOf(subDescriptor.getReturnType(), substitutedSuperReturnType)) { + if (superDescriptor.isVar() && !typeChecker.equalTypes(subDescriptor.getReturnType(), substitutedSuperReturnType)) { return false; } diff --git a/compiler/testData/diagnostics/tests/subtyping/kt3159.kt b/compiler/testData/diagnostics/tests/subtyping/kt3159.kt new file mode 100644 index 00000000000..a72f45f25e1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/subtyping/kt3159.kt @@ -0,0 +1,9 @@ +trait Super { + var v: CharSequence + val v2: CharSequence +} + +class Sub: Super { + override var v: String = "fail" + override val v2: String = "ok" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index d1d421c68a7..e1ec328ac03 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -4105,6 +4105,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage public void testKt2744() throws Exception { doTest("compiler/testData/diagnostics/tests/subtyping/kt2744.kt"); } + + @TestMetadata("kt3159.kt") + public void testKt3159() throws Exception { + doTest("compiler/testData/diagnostics/tests/subtyping/kt3159.kt"); + } @TestMetadata("kt304.kt") public void testKt304() throws Exception { diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java index 56fb2d07414..840aedb0c24 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeErrorMessages.java @@ -79,16 +79,10 @@ public class IdeErrorMessages { "Parameter:{1}", HTML_RENDER_TYPE, HTML_RENDER_TYPE); MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, "Return type is ''{0}'', which is not a subtype of overridden
" + - "{1}", - new Renderer() { - @NotNull - @Override - public String render(@NotNull CallableMemberDescriptor object) { - JetType returnType = object.getReturnType(); - assert returnType != null; - return DescriptorRenderer.HTML.renderType(returnType); - } - }, DescriptorRenderer.HTML); + "{1}", HTML_RENDER_RETURN_TYPE, DescriptorRenderer.HTML); + + MAP.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, "Var-property type is ''{0}'', which is not a type of overridden
" + + "{1}", HTML_RENDER_RETURN_TYPE, DescriptorRenderer.HTML); MAP.put(VAR_OVERRIDDEN_BY_VAL, "Val-property cannot override var-property
" + "{1}", DescriptorRenderer.HTML, DescriptorRenderer.HTML); diff --git a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java index 18e0170bc06..3bdc6cdb262 100644 --- a/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java +++ b/idea/src/org/jetbrains/jet/plugin/highlighter/IdeRenderers.java @@ -20,10 +20,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.descriptors.CallableDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; -import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.diagnostics.Diagnostic; import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1; import org.jetbrains.jet.lang.diagnostics.Errors; @@ -213,4 +210,13 @@ public class IdeRenderers { } }; + public static final Renderer HTML_RENDER_RETURN_TYPE = new Renderer() { + @NotNull + @Override + public String render(@NotNull CallableMemberDescriptor object) { + JetType returnType = object.getReturnType(); + assert returnType != null; + return DescriptorRenderer.HTML.renderType(returnType); + } + }; }