[JVM] Introduce MF Value Classes to frontend

This commit is contained in:
Evgeniy.Zhelenskiy
2021-12-24 04:37:30 +03:00
committed by Space
parent c15b1ec001
commit 7595f798e1
26 changed files with 795 additions and 126 deletions
@@ -400,12 +400,13 @@ public interface Errors {
DiagnosticFactory0<PsiElement> NON_PRIVATE_CONSTRUCTOR_IN_SEALED = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED = DiagnosticFactory0.create(ERROR);
// Inline classes
// Inline classes, Value classes
DiagnosticFactory0<PsiElement> VALUE_CLASS_NOT_TOP_LEVEL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> VALUE_CLASS_NOT_FINAL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtElement> VALUE_CLASS_EMPTY_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtParameter> VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtProperty> PROPERTY_WITH_BACKING_FIELD_INSIDE_VALUE_CLASS = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
DiagnosticFactory0<PsiElement> DELEGATED_PROPERTY_INSIDE_VALUE_CLASS = DiagnosticFactory0.create(ERROR);
@@ -755,8 +755,9 @@ public class DefaultErrorMessages {
MAP.put(VALUE_CLASS_NOT_TOP_LEVEL, "Value classes cannot be local or inner");
MAP.put(VALUE_CLASS_NOT_FINAL, "Value classes can be only final");
MAP.put(ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS, "Primary constructor is required for value class");
MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter"); // +
MAP.put(VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, "Value class primary constructor must only have final read-only (val) property parameter");
MAP.put(INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, "Inline class must have exactly one primary constructor parameter");
MAP.put(VALUE_CLASS_EMPTY_CONSTRUCTOR, "Value class must have at least one primary constructor parameter");
MAP.put(VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER, "Value class primary constructor must only have final read-only (val) property parameters");
MAP.put(PROPERTY_WITH_BACKING_FIELD_INSIDE_VALUE_CLASS, "Value class cannot have properties with backing fields");
MAP.put(DELEGATED_PROPERTY_INSIDE_VALUE_CLASS, "Value class cannot have delegated properties");
MAP.put(VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE, "Value class cannot have value parameter of type ''{0}''", RENDER_TYPE);
@@ -80,31 +80,47 @@ object InlineClassDeclarationChecker : DeclarationChecker {
return
}
val baseParameter = primaryConstructor.valueParameters.singleOrNull()
if (baseParameter == null) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ValueClasses)) {
if (primaryConstructor.valueParameters.isEmpty()) {
(primaryConstructor.valueParameterList ?: declaration).let {
trace.report(Errors.VALUE_CLASS_EMPTY_CONSTRUCTOR.on(it))
return
}
}
} else if (primaryConstructor.valueParameters.size != 1) {
(primaryConstructor.valueParameterList ?: declaration).let {
trace.report(Errors.INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE.on(it))
return
}
}
if (!isParameterAcceptableForInlineClass(baseParameter)) {
trace.report(Errors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER.on(baseParameter))
return
var baseParametersOk = true
for (baseParameter in primaryConstructor.valueParameters) {
if (!isParameterAcceptableForInlineClass(baseParameter)) {
trace.report(Errors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER.on(baseParameter))
baseParametersOk = false
continue
}
val baseParameterType = descriptor.safeAs<ClassDescriptor>()?.defaultType?.substitutedUnderlyingType()
val baseParameterTypeReference = baseParameter.typeReference
if (baseParameterType != null && baseParameterTypeReference != null) {
if (baseParameterType.isInapplicableParameterType()) {
trace.report(Errors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE.on(baseParameterTypeReference, baseParameterType))
baseParametersOk = false
continue
}
if (baseParameterType.isRecursiveInlineClassType()) { // todo check work for MF VC
trace.report(Errors.VALUE_CLASS_CANNOT_BE_RECURSIVE.on(baseParameterTypeReference))
baseParametersOk = false
continue
}
}
}
val baseParameterType = descriptor.safeAs<ClassDescriptor>()?.defaultType?.substitutedUnderlyingType()
val baseParameterTypeReference = baseParameter.typeReference
if (baseParameterType != null && baseParameterTypeReference != null) {
if (baseParameterType.isInapplicableParameterType()) {
trace.report(Errors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE.on(baseParameterTypeReference, baseParameterType))
return
}
if (baseParameterType.isRecursiveInlineClassType()) {
trace.report(Errors.VALUE_CLASS_CANNOT_BE_RECURSIVE.on(baseParameterTypeReference))
return
}
if (!baseParametersOk) {
return
}
for (supertypeEntry in declaration.superTypeListEntries) {
@@ -129,7 +145,8 @@ object InlineClassDeclarationChecker : DeclarationChecker {
}
if (descriptor.getAllSuperClassifiers().any {
it.fqNameUnsafe == StandardNames.FqNames.cloneable || it.fqNameUnsafe == javaLangCloneable }
it.fqNameUnsafe == StandardNames.FqNames.cloneable || it.fqNameUnsafe == javaLangCloneable
}
) {
trace.report(Errors.VALUE_CLASS_CANNOT_BE_CLONEABLE.on(inlineOrValueKeyword))
return