[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
@@ -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")