Improve support of 'lateinit' modifier

- Allow 'lateinit' for inline classes which underlying type
is suitable for 'lateinit'

- K2: report all problems related to 'lateinit' modifier

^KT-55052: Fixed
This commit is contained in:
Vladislav Grechko
2022-11-18 03:22:17 +01:00
committed by teamcity
parent e0c13e5276
commit cd6e865fb3
35 changed files with 406 additions and 84 deletions
@@ -495,7 +495,7 @@ class DeclarationsChecker(
for (parameter in declaration.valueParameters) {
trace.get(PRIMARY_CONSTRUCTOR_PARAMETER, parameter)?.let {
modifiersChecker.checkModifiersForDeclaration(parameter, it)
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, parameter, it)
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, parameter, it, languageVersionSettings)
}
}
@@ -610,7 +610,7 @@ class DeclarationsChecker(
if (containingDeclaration is ClassDescriptor) {
checkMemberProperty(property, propertyDescriptor, containingDeclaration)
}
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, property, propertyDescriptor)
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(trace, property, propertyDescriptor, languageVersionSettings)
checkPropertyInitializer(property, propertyDescriptor)
checkAccessors(property, propertyDescriptor)
checkTypeParameterConstraints(property)
@@ -18,6 +18,9 @@ package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.UnsignedTypes
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptor
@@ -28,10 +31,18 @@ import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.DeclarationsChecker.Companion.hasAccessorImplementation
import org.jetbrains.kotlin.resolve.descriptorUtil.inlineClassRepresentation
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isUnsignedNumberType
object LateinitModifierApplicabilityChecker {
fun checkLateinitModifierApplicability(trace: BindingTrace, ktDeclaration: KtCallableDeclaration, descriptor: VariableDescriptor) {
fun checkLateinitModifierApplicability(
trace: BindingTrace,
ktDeclaration: KtCallableDeclaration,
descriptor: VariableDescriptor,
languageVersionSettings: LanguageVersionSettings
) {
if (!ktDeclaration.hasModifier(KtTokens.LATEINIT_KEYWORD)) return
val variables = when (descriptor) {
@@ -47,10 +58,27 @@ object LateinitModifierApplicabilityChecker {
}
if (type.isInlineClassType()) {
if (UnsignedTypes.isUnsignedType(type)) {
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(ktDeclaration, "is not allowed on $variables of unsigned types"))
} else {
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(ktDeclaration, "is not allowed on $variables of inline class types"))
when {
type.isUnsignedNumberType() -> trace.report(
Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(
ktDeclaration,
"is not allowed on $variables of unsigned types"
)
)
!languageVersionSettings.supportsFeature(LanguageFeature.InlineLateinit) ->
trace.report(
Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(
ktDeclaration,
"is not allowed on $variables of inline class types"
)
)
hasUnderlyingTypeForbiddenForLateinit(type) ->
trace.report(
Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(
ktDeclaration,
"is not allowed on $variables of inline type with underlying type not suitable for lateinit declaration"
)
)
}
}
@@ -100,7 +128,12 @@ object LateinitModifierApplicabilityChecker {
)
)
} else if (!isAbstract && !hasBackingField) {
trace.report(Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(ktDeclaration, "is not allowed on properties without backing field"))
trace.report(
Errors.INAPPLICABLE_LATEINIT_MODIFIER.on(
ktDeclaration,
"is not allowed on properties without backing field"
)
)
}
}
@@ -109,4 +142,26 @@ object LateinitModifierApplicabilityChecker {
}
}
}
private fun hasUnderlyingTypeForbiddenForLateinit(type: KotlinType): Boolean {
fun getUnderlyingType(type: KotlinType): KotlinType {
return (type.constructor.declarationDescriptor as ClassDescriptor).inlineClassRepresentation!!.underlyingType
}
fun isForbiddenForLateinit(type: KotlinType): Boolean {
if (type.isMarkedNullable || TypeUtils.isNullableType(type)) return true
if (KotlinBuiltIns.isPrimitiveType(type)) return true
if (type.isInlineClassType()) {
return isForbiddenForLateinit(getUnderlyingType(type))
}
return false
}
// prevent infinite recursion
if (type.isRecursiveInlineOrValueClassType()) return false
return isForbiddenForLateinit(getUnderlyingType(type))
}
}
@@ -150,7 +150,7 @@ class LocalVariableResolver(
modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(ktProperty, descriptor)
identifierChecker.checkDeclaration(ktProperty, context.trace)
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(context.trace, ktProperty, descriptor)
LateinitModifierApplicabilityChecker.checkLateinitModifierApplicability(context.trace, ktProperty, descriptor, languageVersionSettings)
}
private fun resolveLocalVariableDescriptor(