diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt index 5a1623eb7ab..ce2e55bb808 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DeclarationsChecker.kt @@ -576,27 +576,19 @@ class DeclarationsChecker( } private fun checkPropertyLateInit(property: KtCallableDeclaration, propertyDescriptor: PropertyDescriptor) { - val modifierList = property.modifierList ?: return - val modifier = modifierList.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return + val modifier = property.modifierList?.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return if (!propertyDescriptor.isVar) { trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable properties")) } - var returnTypeIsNullable = true - var returnTypeIsPrimitive = true + val returnType = propertyDescriptor.type - val returnType = propertyDescriptor.returnType - if (returnType != null) { - returnTypeIsNullable = TypeUtils.isNullableType(returnType) - returnTypeIsPrimitive = KotlinBuiltIns.isPrimitiveType(returnType) - } - - if (returnTypeIsNullable) { + if (TypeUtils.isNullableType(returnType)) { trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on nullable properties")) } - if (returnTypeIsPrimitive) { + if (KotlinBuiltIns.isPrimitiveType(returnType)) { trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on primitive type properties")) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt index ef4b8ad2c96..f4575653341 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.resolve +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.descriptors.* @@ -24,9 +25,7 @@ import org.jetbrains.kotlin.descriptors.impl.* import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.KtProperty -import org.jetbrains.kotlin.psi.KtPsiUtil -import org.jetbrains.kotlin.psi.KtVariableDeclaration +import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory @@ -35,6 +34,7 @@ import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.source.toSourceElement import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.* import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo @@ -120,13 +120,42 @@ class LocalVariableResolver( typeInfo = noTypeInfo(context) } - ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, propertyDescriptor) + checkLocalVariableDeclaration(context, propertyDescriptor, property) - modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(property, propertyDescriptor) - identifierChecker.checkDeclaration(property, context.trace) return Pair(typeInfo.replaceType(dataFlowAnalyzer.checkStatementType(property, context)), propertyDescriptor) } + private fun checkLocalVariableDeclaration(context: ExpressionTypingContext, descriptor: VariableDescriptor, ktProperty: KtProperty) { + ExpressionTypingUtils.checkVariableShadowing(context.scope, context.trace, descriptor) + + modifiersChecker.withTrace(context.trace).checkModifiersForLocalDeclaration(ktProperty, descriptor) + identifierChecker.checkDeclaration(ktProperty, context.trace) + + checkLocalVariableLateinit(context.trace, descriptor, ktProperty) + } + + private fun checkLocalVariableLateinit(trace: BindingTrace, descriptor: VariableDescriptor, ktProperty: KtProperty) { + val modifierList = ktProperty.modifierList ?: return + val modifier = modifierList.getModifier(KtTokens.LATEINIT_KEYWORD) ?: return + val returnType = descriptor.type + + if (!descriptor.isVar) { + trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is allowed only on mutable local variables")) + } + + if (TypeUtils.isNullableType(returnType)) { + trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on local variables of nullable types")) + } + + if (KotlinBuiltIns.isPrimitiveType(returnType)) { + trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on local variables of primitive types")) + } + + if (ktProperty.hasDelegateExpressionOrInitializer()) { + trace.report(INAPPLICABLE_LATEINIT_MODIFIER.on(modifier, "is not allowed on variables with initializer or on local delegated properties")) + } + } + private fun resolveLocalVariableDescriptor( scope: LexicalScope, variable: KtVariableDeclaration, diff --git a/compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.kt b/compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.kt new file mode 100644 index 00000000000..3e767514fc8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.kt @@ -0,0 +1,17 @@ +// !DIAGNOSTICS: -UNUSED_VALUE -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE + +import kotlin.reflect.KProperty + +object Delegate { + operator fun getValue(instance: Any?, property: KProperty<*>) : String = "" + operator fun setValue(instance: Any?, property: KProperty<*>, value: String) {} +} + + +fun test() { + lateinit val test0: Any + lateinit var test1: Int + lateinit var test2: Any? + lateinit var test3: String = "" + lateinit var test4 by Delegate +} diff --git a/compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.txt b/compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.txt new file mode 100644 index 00000000000..c77c45304f8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.txt @@ -0,0 +1,12 @@ +package + +public fun test(): kotlin.Unit + +public object Delegate { + private constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final operator fun getValue(/*0*/ instance: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): kotlin.String + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final operator fun setValue(/*0*/ instance: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>, /*2*/ value: kotlin.String): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 046fc232ca2..5f30bf47cf8 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -16263,6 +16263,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/properties/localLateinit"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.ANY, true); } + @TestMetadata("inapplicableLateinitModifier.kt") + public void testInapplicableLateinitModifier() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/inapplicableLateinitModifier.kt"); + doTest(fileName); + } + @TestMetadata("localLateinit.kt") public void testLocalLateinit() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/localLateinit.kt");