KT-3159 Disallow overriding var with different type #KT-3159 fixed
This commit is contained in:
committed by
Andrey Breslav
parent
e9613b95ac
commit
e89a8c684f
@@ -221,6 +221,8 @@ public interface Errors {
|
|||||||
DiagnosticFactory3.create(ERROR, VISIBILITY_MODIFIER);
|
DiagnosticFactory3.create(ERROR, VISIBILITY_MODIFIER);
|
||||||
DiagnosticFactory2<JetNamedDeclaration, CallableMemberDescriptor, CallableMemberDescriptor> RETURN_TYPE_MISMATCH_ON_OVERRIDE =
|
DiagnosticFactory2<JetNamedDeclaration, CallableMemberDescriptor, CallableMemberDescriptor> RETURN_TYPE_MISMATCH_ON_OVERRIDE =
|
||||||
DiagnosticFactory2.create(ERROR, DECLARATION_RETURN_TYPE);
|
DiagnosticFactory2.create(ERROR, DECLARATION_RETURN_TYPE);
|
||||||
|
DiagnosticFactory2<JetNamedDeclaration, CallableMemberDescriptor, CallableMemberDescriptor> PROPERTY_TYPE_MISMATCH_ON_OVERRIDE =
|
||||||
|
DiagnosticFactory2.create(ERROR, DECLARATION_RETURN_TYPE);
|
||||||
|
|
||||||
DiagnosticFactory2<PsiElement, JetClassOrObject, CallableMemberDescriptor> ABSTRACT_MEMBER_NOT_IMPLEMENTED =
|
DiagnosticFactory2<PsiElement, JetClassOrObject, CallableMemberDescriptor> ABSTRACT_MEMBER_NOT_IMPLEMENTED =
|
||||||
DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2.create(ERROR);
|
||||||
|
|||||||
+3
@@ -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}",
|
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);
|
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,
|
MAP.put(VAR_OVERRIDDEN_BY_VAL, "Var-property {0} cannot be overridden by val-property {1}", DescriptorRenderer.TEXT,
|
||||||
DescriptorRenderer.TEXT);
|
DescriptorRenderer.TEXT);
|
||||||
|
|
||||||
|
|||||||
@@ -585,6 +585,8 @@ public class OverrideResolver {
|
|||||||
|
|
||||||
void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
|
void returnTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
|
||||||
|
|
||||||
|
void propertyTypeMismatchOnOverride(@NotNull CallableMemberDescriptor overridden);
|
||||||
|
|
||||||
void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden);
|
void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden);
|
||||||
|
|
||||||
void cannotOverrideInvisibleMember(@NotNull CallableMemberDescriptor invisibleOverridden);
|
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
|
@Override
|
||||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
||||||
if (!kindMismatchError) {
|
if (!kindMismatchError) {
|
||||||
@@ -674,7 +684,11 @@ public class OverrideResolver {
|
|||||||
reportError.overridingFinalMember(overridden);
|
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);
|
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
|
@Override
|
||||||
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
public void varOverriddenByVal(@NotNull CallableMemberDescriptor overridden) {
|
||||||
throw new IllegalStateException("Component functions are not properties");
|
throw new IllegalStateException("Component functions are not properties");
|
||||||
|
|||||||
@@ -221,6 +221,21 @@ public class OverridingUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReturnTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull CallableDescriptor superDescriptor, @NotNull CallableDescriptor subDescriptor) {
|
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<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
|
List<TypeParameterDescriptor> superTypeParameters = superDescriptor.getTypeParameters();
|
||||||
List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
|
List<TypeParameterDescriptor> subTypeParameters = subDescriptor.getTypeParameters();
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
|
Map<TypeConstructor, TypeProjection> substitutionContext = Maps.newHashMap();
|
||||||
@@ -231,12 +246,14 @@ public class OverridingUtil {
|
|||||||
superTypeParameter.getTypeConstructor(),
|
superTypeParameter.getTypeConstructor(),
|
||||||
new TypeProjection(subTypeParameter.getDefaultType()));
|
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
|
public static boolean isPropertyTypeOkForOverride(@NotNull JetTypeChecker typeChecker, @NotNull PropertyDescriptor superDescriptor, @NotNull PropertyDescriptor subDescriptor) {
|
||||||
TypeSubstitutor typeSubstitutor = TypeSubstitutor.create(substitutionContext);
|
TypeSubstitutor typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor);
|
||||||
JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE);
|
JetType substitutedSuperReturnType = typeSubstitutor.substitute(superDescriptor.getReturnType(), Variance.OUT_VARIANCE);
|
||||||
assert substitutedSuperReturnType != null;
|
assert substitutedSuperReturnType != null;
|
||||||
if (!typeChecker.isSubtypeOf(subDescriptor.getReturnType(), substitutedSuperReturnType)) {
|
if (superDescriptor.isVar() && !typeChecker.equalTypes(subDescriptor.getReturnType(), substitutedSuperReturnType)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
trait Super {
|
||||||
|
var v: CharSequence
|
||||||
|
val v2: CharSequence
|
||||||
|
}
|
||||||
|
|
||||||
|
class Sub: Super {
|
||||||
|
override var v: <!PROPERTY_TYPE_MISMATCH_ON_OVERRIDE!>String<!> = "fail"
|
||||||
|
override val v2: String = "ok"
|
||||||
|
}
|
||||||
@@ -4105,6 +4105,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
|||||||
public void testKt2744() throws Exception {
|
public void testKt2744() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/subtyping/kt2744.kt");
|
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")
|
@TestMetadata("kt304.kt")
|
||||||
public void testKt304() throws Exception {
|
public void testKt304() throws Exception {
|
||||||
|
|||||||
@@ -79,16 +79,10 @@ public class IdeErrorMessages {
|
|||||||
"<tr><td>Parameter:</td><td>{1}</td></tr></table></html>", HTML_RENDER_TYPE, HTML_RENDER_TYPE);
|
"<tr><td>Parameter:</td><td>{1}</td></tr></table></html>", HTML_RENDER_TYPE, HTML_RENDER_TYPE);
|
||||||
|
|
||||||
MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, "<html>Return type is ''{0}'', which is not a subtype of overridden<br/>" +
|
MAP.put(RETURN_TYPE_MISMATCH_ON_OVERRIDE, "<html>Return type is ''{0}'', which is not a subtype of overridden<br/>" +
|
||||||
"{1}</html>",
|
"{1}</html>", HTML_RENDER_RETURN_TYPE, DescriptorRenderer.HTML);
|
||||||
new Renderer<CallableMemberDescriptor>() {
|
|
||||||
@NotNull
|
MAP.put(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE, "<html>Var-property type is ''{0}'', which is not a type of overridden<br/>" +
|
||||||
@Override
|
"{1}</html>", HTML_RENDER_RETURN_TYPE, DescriptorRenderer.HTML);
|
||||||
public String render(@NotNull CallableMemberDescriptor object) {
|
|
||||||
JetType returnType = object.getReturnType();
|
|
||||||
assert returnType != null;
|
|
||||||
return DescriptorRenderer.HTML.renderType(returnType);
|
|
||||||
}
|
|
||||||
}, DescriptorRenderer.HTML);
|
|
||||||
|
|
||||||
MAP.put(VAR_OVERRIDDEN_BY_VAL, "<html>Val-property cannot override var-property<br />" +
|
MAP.put(VAR_OVERRIDDEN_BY_VAL, "<html>Val-property cannot override var-property<br />" +
|
||||||
"{1}</html>", DescriptorRenderer.HTML, DescriptorRenderer.HTML);
|
"{1}</html>", DescriptorRenderer.HTML, DescriptorRenderer.HTML);
|
||||||
|
|||||||
@@ -20,10 +20,7 @@ import com.intellij.psi.PsiElement;
|
|||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
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.diagnostics.Diagnostic;
|
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
|
||||||
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1;
|
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithParameters1;
|
||||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||||
@@ -213,4 +210,13 @@ public class IdeRenderers {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static final Renderer<CallableMemberDescriptor> HTML_RENDER_RETURN_TYPE = new Renderer<CallableMemberDescriptor>() {
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public String render(@NotNull CallableMemberDescriptor object) {
|
||||||
|
JetType returnType = object.getReturnType();
|
||||||
|
assert returnType != null;
|
||||||
|
return DescriptorRenderer.HTML.renderType(returnType);
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user