[IR] Support user-defined equals for MFVC
Signed-off-by: Evgeniy.Zhelenskiy <Evgeniy.Zhelenskiy@jetbrains.com> #KT-1179
This commit is contained in:
committed by
Space Team
parent
51f9f31a0a
commit
9f01ccc304
@@ -420,8 +420,9 @@ public interface Errors {
|
||||
DiagnosticFactory0<PsiElement> VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> VALUE_CLASS_CANNOT_EXTEND_CLASSES = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> VALUE_CLASS_CANNOT_BE_RECURSIVE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_VALUE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_VALUE_CLASS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> RESERVED_MEMBER_INSIDE_VALUE_CLASS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<KtTypeReference> TYPE_ARGUMENT_ON_TYPED_VALUE_CLASS_EQUALS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> INNER_CLASS_INSIDE_VALUE_CLASS = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> VALUE_CLASS_CANNOT_BE_CLONEABLE = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> INLINE_CLASS_DEPRECATED = DiagnosticFactory0.create(WARNING);
|
||||
|
||||
+4
-3
@@ -795,14 +795,15 @@ public class DefaultErrorMessages {
|
||||
MAP.put(VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION, "Value class cannot implement an interface by delegation if expression is not a parameter");
|
||||
MAP.put(VALUE_CLASS_CANNOT_EXTEND_CLASSES, "Value class cannot extend classes");
|
||||
MAP.put(VALUE_CLASS_CANNOT_BE_RECURSIVE, "Value class cannot be recursive");
|
||||
MAP.put(RESERVED_MEMBER_INSIDE_VALUE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING);
|
||||
MAP.put(SECONDARY_CONSTRUCTOR_WITH_BODY_INSIDE_VALUE_CLASS, "Secondary constructors with bodies are reserved for for future releases");
|
||||
MAP.put(RESERVED_MEMBER_INSIDE_VALUE_CLASS, "Member with the name ''{0}'' is reserved for future releases", STRING);
|
||||
MAP.put(TYPE_ARGUMENT_ON_TYPED_VALUE_CLASS_EQUALS, "Type arguments for typed value class equals must be only star projections");
|
||||
MAP.put(INNER_CLASS_INSIDE_VALUE_CLASS, "Value class cannot have inner classes");
|
||||
MAP.put(VALUE_CLASS_CANNOT_BE_CLONEABLE, "Value class cannot be Cloneable");
|
||||
MAP.put(INLINE_CLASS_DEPRECATED, "'inline' modifier is deprecated. Use 'value' instead");
|
||||
MAP.put(VALUE_CLASS_CANNOT_HAVE_CONTEXT_RECEIVERS, "Value classes cannot have context receivers");
|
||||
MAP.put(INEFFICIENT_EQUALS_OVERRIDING_IN_INLINE_CLASS,
|
||||
"Overriding ''equals'' from ''Any'' in inline class without operator ''equals(other: {0}): Boolean'' leads to boxing on every equality comparison",
|
||||
MAP.put(INEFFICIENT_EQUALS_OVERRIDING_IN_VALUE_CLASS,
|
||||
"Overriding ''equals'' from ''Any'' in value class without operator ''equals(other: {0}): Boolean'' leads to boxing on every equality comparison",
|
||||
RENDER_TYPE);
|
||||
|
||||
MAP.put(RESULT_CLASS_IN_RETURN_TYPE, "'kotlin.Result' cannot be used as a return type");
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.isTypedEqualsInInlineClass
|
||||
import org.jetbrains.kotlin.descriptors.isTypedEqualsInValueClass
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
@@ -52,8 +52,8 @@ object OperatorModifierChecker {
|
||||
functionDescriptor.name == OperatorNameConventions.PROVIDE_DELEGATE ->
|
||||
checkSupportsFeature(LanguageFeature.OperatorProvideDelegate, languageVersionSettings, diagnosticHolder, modifier)
|
||||
|
||||
functionDescriptor.isTypedEqualsInInlineClass() ->
|
||||
checkSupportsFeature(LanguageFeature.CustomEqualsInInlineClasses, languageVersionSettings, diagnosticHolder, modifier)
|
||||
functionDescriptor.isTypedEqualsInValueClass() ->
|
||||
checkSupportsFeature(LanguageFeature.CustomEqualsInValueClasses, languageVersionSettings, diagnosticHolder, modifier)
|
||||
}
|
||||
|
||||
if (functionDescriptor.name in REM_TO_MOD_OPERATION_NAMES.values &&
|
||||
|
||||
+13
-9
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections
|
||||
|
||||
private val javaLangCloneable = FqNameUnsafe("java.lang.Cloneable")
|
||||
|
||||
object InlineClassDeclarationChecker : DeclarationChecker {
|
||||
object ValueClassDeclarationChecker : DeclarationChecker {
|
||||
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||
if (declaration !is KtClass) return
|
||||
if (descriptor !is ClassDescriptor || !descriptor.isInline && !descriptor.isValue) return
|
||||
@@ -166,20 +166,16 @@ object InlineClassDeclarationChecker : DeclarationChecker {
|
||||
context.trace.bindingContext.get(BindingContext.FUNCTION, declaration)
|
||||
|
||||
fun isUntypedEquals(declaration: KtNamedFunction): Boolean = getFunctionDescriptor(declaration)?.overridesEqualsFromAny() ?: false
|
||||
fun isTypedEquals(declaration: KtNamedFunction): Boolean = getFunctionDescriptor(declaration)?.isTypedEqualsInInlineClass() ?: false
|
||||
fun isTypedEquals(declaration: KtNamedFunction): Boolean = getFunctionDescriptor(declaration)?.isTypedEqualsInValueClass() ?: false
|
||||
fun KtClass.namedFunctions() = declarations.filterIsInstance<KtNamedFunction>()
|
||||
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.CustomEqualsInInlineClasses)) {
|
||||
if (context.languageVersionSettings.supportsFeature(LanguageFeature.CustomEqualsInValueClasses)) {
|
||||
val typedEquals = declaration.namedFunctions().firstOrNull { isTypedEquals(it) }
|
||||
|
||||
if (typedEquals?.typeParameters?.isNotEmpty() == true) {
|
||||
trace.report(Errors.TYPE_PARAMETERS_NOT_ALLOWED.on(typedEquals))
|
||||
}
|
||||
|
||||
declaration.namedFunctions().singleOrNull { isUntypedEquals(it) }?.apply {
|
||||
if (typedEquals == null) {
|
||||
trace.report(
|
||||
Errors.INEFFICIENT_EQUALS_OVERRIDING_IN_INLINE_CLASS.on(
|
||||
Errors.INEFFICIENT_EQUALS_OVERRIDING_IN_VALUE_CLASS.on(
|
||||
this@apply,
|
||||
descriptor.defaultType.replaceArgumentsWithStarProjections()
|
||||
)
|
||||
@@ -255,10 +251,18 @@ class ReservedMembersAndConstructsForInlineClass : DeclarationChecker {
|
||||
val functionName = descriptor.name.asString()
|
||||
if (functionName in boxAndUnboxNames
|
||||
|| (functionName in equalsAndHashCodeNames
|
||||
&& !context.languageVersionSettings.supportsFeature(LanguageFeature.CustomEqualsInInlineClasses))
|
||||
&& !context.languageVersionSettings.supportsFeature(LanguageFeature.CustomEqualsInValueClasses))
|
||||
) {
|
||||
val nameIdentifier = ktFunction.nameIdentifier ?: return
|
||||
context.trace.report(Errors.RESERVED_MEMBER_INSIDE_VALUE_CLASS.on(nameIdentifier, functionName))
|
||||
} else if (descriptor.isTypedEqualsInValueClass()) {
|
||||
if (descriptor.typeParameters.isNotEmpty()) {
|
||||
context.trace.report(Errors.TYPE_PARAMETERS_NOT_ALLOWED.on(declaration))
|
||||
}
|
||||
val parameterType = descriptor.valueParameters.first()?.type
|
||||
if (parameterType != null && parameterType.arguments.any { !it.isStarProjection }) {
|
||||
context.trace.report(Errors.TYPE_ARGUMENT_ON_TYPED_VALUE_CLASS_EQUALS.on(declaration.valueParameters[0].typeReference!!))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user