[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
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -32113,6 +32114,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/valueClasses/propertiesWithBackingFieldsInsideValueClass.kt");
}
@Test
@TestMetadata("recursiveMultiFieldValueClasses.kt")
public void testRecursiveMultiFieldValueClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/recursiveMultiFieldValueClasses.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
}
@Test
@TestMetadata("recursiveValueClasses.kt")
public void testRecursiveValueClasses() throws Exception {
@@ -32167,6 +32174,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/valueClasses/valueClassWithForbiddenUnderlyingType.kt");
}
@Test
@TestMetadata("valueClassWithForbiddenUnderlyingTypeMultiField.kt")
public void testValueClassWithForbiddenUnderlyingTypeMultiField() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/valueClassWithForbiddenUnderlyingTypeMultiField.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
}
@Test
@TestMetadata("valueClassesInsideAnnotations.kt")
public void testValueClassesInsideAnnotations() throws Exception {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.test.runners;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.util.KtTestUtil;
import org.jetbrains.kotlin.test.utils.TransformersFunctions;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -32113,6 +32114,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/valueClasses/propertiesWithBackingFieldsInsideValueClass.kt");
}
@Test
@TestMetadata("recursiveMultiFieldValueClasses.kt")
public void testRecursiveMultiFieldValueClasses() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/recursiveMultiFieldValueClasses.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
}
@Test
@TestMetadata("recursiveValueClasses.kt")
public void testRecursiveValueClasses() throws Exception {
@@ -32167,6 +32174,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/valueClasses/valueClassWithForbiddenUnderlyingType.kt");
}
@Test
@TestMetadata("valueClassWithForbiddenUnderlyingTypeMultiField.kt")
public void testValueClassWithForbiddenUnderlyingTypeMultiField() throws Exception {
runTest("compiler/testData/diagnostics/tests/valueClasses/valueClassWithForbiddenUnderlyingTypeMultiField.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
}
@Test
@TestMetadata("valueClassesInsideAnnotations.kt")
public void testValueClassesInsideAnnotations() throws Exception {
@@ -405,6 +405,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val VALUE_CLASS_NOT_FINAL by error<KtDeclaration>(PositioningStrategy.MODALITY_MODIFIER)
val ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS by error<KtDeclaration>(PositioningStrategy.INLINE_OR_VALUE_MODIFIER)
val INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE by error<KtElement>()
val VALUE_CLASS_EMPTY_CONSTRUCTOR by error<KtElement>()
val VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER by error<KtParameter>()
val PROPERTY_WITH_BACKING_FIELD_INSIDE_VALUE_CLASS by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
val DELEGATED_PROPERTY_INSIDE_VALUE_CLASS by error<PsiElement>()
@@ -306,6 +306,7 @@ object FirErrors {
val VALUE_CLASS_NOT_FINAL by error0<KtDeclaration>(SourceElementPositioningStrategies.MODALITY_MODIFIER)
val ABSENCE_OF_PRIMARY_CONSTRUCTOR_FOR_VALUE_CLASS by error0<KtDeclaration>(SourceElementPositioningStrategies.INLINE_OR_VALUE_MODIFIER)
val INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE by error0<KtElement>()
val VALUE_CLASS_EMPTY_CONSTRUCTOR by error0<KtElement>()
val VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER by error0<KtParameter>()
val PROPERTY_WITH_BACKING_FIELD_INSIDE_VALUE_CLASS by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
val DELEGATED_PROPERTY_INSIDE_VALUE_CLASS by error0<PsiElement>()
@@ -15,18 +15,21 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.hasModifier
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOnWithSuppression
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableReference
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.resolve.fullyExpandedType
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.StandardClassIds
object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
@@ -60,8 +63,9 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
}
var primaryConstructor: FirConstructor? = null
var primaryConstructorParameter: FirValueParameter? = null
var primaryConstructorProperty: FirProperty? = null
var primaryConstructorParametersByName = mapOf<Name, FirValueParameter>()
val primaryConstructorPropertiesByName = mutableMapOf<Name, FirProperty>()
var primaryConstructorParametersSymbolsSet = setOf<FirValueParameterSymbol>()
for (innerDeclaration in declaration.declarations) {
when (innerDeclaration) {
@@ -69,7 +73,9 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
when {
innerDeclaration.isPrimary -> {
primaryConstructor = innerDeclaration
primaryConstructorParameter = innerDeclaration.valueParameters.singleOrNull()
primaryConstructorParametersByName = innerDeclaration.valueParameters.associateBy { it.name }
primaryConstructorParametersSymbolsSet =
primaryConstructorParametersByName.map { (_, parameter) -> parameter.symbol }.toSet()
}
innerDeclaration.body != null -> {
@@ -100,7 +106,7 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
if (innerDeclaration.isSynthetic) {
val symbol = innerDeclaration.initializer?.toResolvedCallableSymbol()
if (context.languageVersionSettings.supportsFeature(LanguageFeature.InlineClassImplementationByDelegation) &&
symbol != null && symbol == primaryConstructorParameter?.symbol
symbol != null && symbol in primaryConstructorParametersSymbolsSet
) {
continue
}
@@ -115,8 +121,8 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
}
}
is FirProperty -> {
if (innerDeclaration.isRelatedToParameter(primaryConstructorParameter)) {
primaryConstructorProperty = innerDeclaration
if (innerDeclaration.isRelatedToParameter(primaryConstructorParametersByName[innerDeclaration.name])) {
primaryConstructorPropertiesByName[innerDeclaration.name] = innerDeclaration
} else {
when {
innerDeclaration.delegate != null ->
@@ -147,35 +153,42 @@ object FirInlineClassDeclarationChecker : FirRegularClassChecker() {
return
}
if (primaryConstructorParameter == null) {
if (context.languageVersionSettings.supportsFeature(LanguageFeature.ValueClasses)) {
if (primaryConstructorParametersByName.isEmpty()) {
reporter.reportOnWithSuppression(primaryConstructor, FirErrors.VALUE_CLASS_EMPTY_CONSTRUCTOR, context)
return
}
} else if (primaryConstructorParametersByName.size != 1) {
reporter.reportOnWithSuppression(primaryConstructor, FirErrors.INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE, context)
return
}
withSuppressedDiagnostics(primaryConstructor, context) { context ->
withSuppressedDiagnostics(primaryConstructorParameter, context) { context ->
when {
primaryConstructorParameter.isNotFinalReadOnly(primaryConstructorProperty) ->
reporter.reportOn(
primaryConstructorParameter.source,
FirErrors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER,
context
)
for ((name, primaryConstructorParameter) in primaryConstructorParametersByName) {
withSuppressedDiagnostics(primaryConstructor, context) { context ->
withSuppressedDiagnostics(primaryConstructorParameter, context) { context ->
when {
primaryConstructorParameter.isNotFinalReadOnly(primaryConstructorPropertiesByName[name]) ->
reporter.reportOn(
primaryConstructorParameter.source,
FirErrors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER,
context
)
primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() ->
reporter.reportOn(
primaryConstructorParameter.returnTypeRef.source,
FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE,
primaryConstructorParameter.returnTypeRef.coneType,
context
)
primaryConstructorParameter.returnTypeRef.isInapplicableParameterType() ->
reporter.reportOn(
primaryConstructorParameter.returnTypeRef.source,
FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE,
primaryConstructorParameter.returnTypeRef.coneType,
context
)
primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) ->
reporter.reportOnWithSuppression(
primaryConstructorParameter.returnTypeRef,
FirErrors.VALUE_CLASS_CANNOT_BE_RECURSIVE,
context
)
primaryConstructorParameter.returnTypeRef.coneType.isRecursiveInlineClassType(context.session) ->
reporter.reportOnWithSuppression(
primaryConstructorParameter.returnTypeRef,
FirErrors.VALUE_CLASS_CANNOT_BE_RECURSIVE,
context
)
}
}
}
}
@@ -534,6 +534,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNO
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_EXTEND_CLASSES
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_EMPTY_CONSTRUCTOR
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_NOT_FINAL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_NOT_TOP_LEVEL
@@ -1150,13 +1151,14 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
)
// Value classes
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(VALUE_CLASS_NOT_TOP_LEVEL, "Value class cannot be local or inner")
map.put(VALUE_CLASS_NOT_FINAL, "Value class 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(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 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")
@@ -47482,6 +47482,28 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/valueClasses")
@TestDataPath("$PROJECT_ROOT")
public class ValueClasses {
@Test
public void testAllFilesPresentInValueClasses() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/valueClasses"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
}
@Test
@TestMetadata("equality.kt")
public void testEquality() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/equality.kt", TransformersFunctions.getReplaceOptionalJvmInlineAnnotationWithReal());
}
@Test
@TestMetadata("equality.kt")
public void testEquality_valueClasses() throws Exception {
runTest("compiler/testData/codegen/box/valueClasses/equality.kt", TransformersFunctions.getRemoveOptionalJvmInlineAnnotation());
}
}
@Nested
@TestMetadata("compiler/testData/codegen/box/vararg")
@TestDataPath("$PROJECT_ROOT")