From 3bae430d4912533de65a6fdc4b24bbdd1095dac5 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Wed, 31 May 2017 13:52:07 +0300 Subject: [PATCH] Resolve lateinit variables Do not report UNINITIALIZED_VARIABLE on lateinit variables Provide delegating constructors for descriptors for compatibility. --- .../binding/CodegenAnnotatingVisitor.java | 2 -- .../cfg/ControlFlowInformationProvider.kt | 4 ++- .../impl/LocalVariableDescriptor.java | 30 +++++++++++++++++++ .../impl/SyntheticFieldDescriptor.kt | 3 +- .../kotlin/resolve/DescriptorResolver.java | 2 -- .../kotlin/resolve/LocalVariableResolver.kt | 3 ++ .../jetbrains/kotlin/resolve/TypeResolver.kt | 2 ++ .../DoubleColonExpressionResolver.kt | 4 +-- .../jvm/descriptors/SharedVariablesManager.kt | 2 +- .../ir/descriptors/IrDelegateDescriptor.kt | 1 + .../IrTemporaryVariableDescriptor.kt | 2 ++ .../util/FakeCallableDescriptorForObject.kt | 2 ++ .../properties/localLateinit/uninitialized.kt | 22 ++++++++++++++ .../localLateinit/uninitialized.txt | 6 ++++ .../checkers/DiagnosticsTestGenerated.java | 6 ++++ .../descriptors/PropertyDescriptor.java | 2 -- .../descriptors/ValueParameterDescriptor.kt | 2 ++ .../descriptors/VariableDescriptor.java | 2 ++ .../translate/context/TranslationContext.java | 2 -- 19 files changed, 86 insertions(+), 13 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.kt create mode 100644 compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.txt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java index bf17c9da8ce..5491b9dbf94 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/binding/CodegenAnnotatingVisitor.java @@ -396,8 +396,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid { Annotations.Companion.getEMPTY(), Name.identifier(variableDescriptor.getName().asString() + "$metadata"), ReflectionTypes.Companion.createKPropertyStarType(DescriptorUtilsKt.getModule(variableDescriptor)), - false, - false, SourceElement.NO_SOURCE ); bindingTrace.record(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor, metadataVariableDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index 7d4a9569567..6920f6f2804 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -354,7 +354,9 @@ class ControlFlowInformationProvider private constructor( } } is VariableDescriptor -> - report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt) + if (!variableDescriptor.isLateInit) { + report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt) + } } } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java index 78aa8bab775..0d7dd9e9549 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/LocalVariableDescriptor.java @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor; public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl implements VariableDescriptorWithAccessors { private final boolean isDelegated; + private final boolean isLateInit; private LocalVariableAccessorDescriptor.Getter getter; private LocalVariableAccessorDescriptor.Setter setter; @@ -36,10 +37,34 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm @Nullable KotlinType type, boolean mutable, boolean isDelegated, + boolean isLateInit, @NotNull SourceElement source ) { super(containingDeclaration, annotations, name, type, mutable, source); this.isDelegated = isDelegated; + this.isLateInit = isLateInit; + } + + public LocalVariableDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull Annotations annotations, + @NotNull Name name, + @Nullable KotlinType type, + boolean mutable, + boolean isDelegated, + @NotNull SourceElement source + ) { + this(containingDeclaration, annotations, name, type, mutable, isDelegated, false, source); + } + + public LocalVariableDescriptor( + @NotNull DeclarationDescriptor containingDeclaration, + @NotNull Annotations annotations, + @NotNull Name name, + @Nullable KotlinType type, + @NotNull SourceElement source + ) { + this(containingDeclaration, annotations, name, type, false, false, false, source); } @Override @@ -89,4 +114,9 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm public boolean isDelegated() { return isDelegated; } + + @Override + public boolean isLateInit() { + return isLateInit; + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/SyntheticFieldDescriptor.kt b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/SyntheticFieldDescriptor.kt index a0721619165..bff25f7a188 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/SyntheticFieldDescriptor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/SyntheticFieldDescriptor.kt @@ -29,7 +29,8 @@ class SyntheticFieldDescriptor private constructor( accessorDescriptor: PropertyAccessorDescriptor, property: KtProperty ): LocalVariableDescriptor(accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME, - propertyDescriptor.type, propertyDescriptor.isVar, false, property.toSourceElement()) { + propertyDescriptor.type, propertyDescriptor.isVar, false, false, + property.toSourceElement()) { constructor(accessorDescriptor: PropertyAccessorDescriptor, property: KtProperty): this(accessorDescriptor.correspondingProperty, accessorDescriptor, property) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java index 911e92cf700..a9789071142 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DescriptorResolver.java @@ -675,8 +675,6 @@ public class DescriptorResolver { annotationResolver.resolveAnnotationsWithArguments(scope, parameter.getModifierList(), trace), KtPsiUtil.safeName(parameter.getName()), approximatedType, - false, - false, KotlinSourceElementKt.toSourceElement(parameter) ); trace.record(BindingContext.VALUE_PARAMETER, parameter, variableDescriptor); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt index 9e516d95f0a..ef4b8ad2c96 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/LocalVariableResolver.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.annotations.Annotations 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 @@ -195,6 +196,7 @@ class LocalVariableResolver( trace: BindingTrace ): LocalVariableDescriptor { val hasDelegate = variable is KtProperty && variable.hasDelegate() + val hasLateinit = variable.hasModifier(KtTokens.LATEINIT_KEYWORD) val variableDescriptor = LocalVariableDescriptor( scope.ownerDescriptor, annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace), @@ -207,6 +209,7 @@ class LocalVariableResolver( type, variable.isVar, hasDelegate, + hasLateinit, variable.toSourceElement() ) trace.record(BindingContext.VARIABLE, variable, variableDescriptor) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt index a0eea798d74..b0c7e05dc82 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TypeResolver.kt @@ -275,6 +275,8 @@ class TypeResolver( override fun isVar() = false + override fun isLateInit() = false + override fun getCompileTimeInitializer() = null override fun accept(visitor: DeclarationDescriptorVisitor, data: D): R { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt index 6d9023ba916..43628f02ac4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/DoubleColonExpressionResolver.kt @@ -592,8 +592,8 @@ class DoubleColonExpressionResolver( internal fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) { val localVariable = LocalVariableDescriptor( - context.scope.ownerDescriptor, Annotations.EMPTY, Name.special(""), referenceType, /* mutable = */ false, - /* isDelegated = */ false, expression.toSourceElement() + context.scope.ownerDescriptor, Annotations.EMPTY, Name.special(""), referenceType, + expression.toSourceElement() ) context.trace.record(BindingContext.VARIABLE, expression, localVariable) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SharedVariablesManager.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SharedVariablesManager.kt index 6d5f582af9a..53b621866dc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SharedVariablesManager.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/descriptors/SharedVariablesManager.kt @@ -111,7 +111,7 @@ class JvmSharedVariablesManager(val builtIns: KotlinBuiltIns) : SharedVariablesM LocalVariableDescriptor( variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name, getSharedVariableType(variableDescriptor.type), - false, false, variableDescriptor.source + false, false, variableDescriptor.isLateInit, variableDescriptor.source ) override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt index 27d112c696a..5b33a438b42 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrDelegateDescriptor.kt @@ -136,6 +136,7 @@ class IrLocalDelegatedPropertyDelegateDescriptorImpl( override fun getCompileTimeInitializer(): ConstantValue<*>? = null override fun isVar(): Boolean = false + override fun isLateInit(): Boolean = false override fun substitute(substitutor: TypeSubstitutor): VariableDescriptor? = throw UnsupportedOperationException() override fun getVisibility(): Visibility = Visibilities.LOCAL diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrTemporaryVariableDescriptor.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrTemporaryVariableDescriptor.kt index 47c1b8d8cfe..8e7cfaf1b35 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrTemporaryVariableDescriptor.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/IrTemporaryVariableDescriptor.kt @@ -44,6 +44,8 @@ class IrTemporaryVariableDescriptorImpl( override fun isVar(): Boolean = isMutable + override fun isLateInit(): Boolean = false + override fun accept(visitor: DeclarationDescriptorVisitor, data: D): R = visitor.visitVariableDescriptor(this, data) } \ No newline at end of file diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/FakeCallableDescriptorForObject.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/FakeCallableDescriptorForObject.kt index babf235a267..a3355645b97 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/FakeCallableDescriptorForObject.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/util/FakeCallableDescriptorForObject.kt @@ -67,6 +67,8 @@ open class FakeCallableDescriptorForObject( override fun isConst(): Boolean = false + override fun isLateInit(): Boolean = false + override fun equals(other: Any?) = other is FakeCallableDescriptorForObject && classDescriptor == other.classDescriptor override fun hashCode() = classDescriptor.hashCode() diff --git a/compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.kt b/compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.kt new file mode 100644 index 00000000000..da073e7cd81 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.kt @@ -0,0 +1,22 @@ +fun test1() { + lateinit var s: String + s.length +} + +fun test2() { + lateinit var s: String + run { + s = "" + } + s.length +} + +fun almostAlwaysTrue(): Boolean = true + +fun test3() { + lateinit var s: String + if (almostAlwaysTrue()) { + s = "" + } + s.length +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.txt b/compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.txt new file mode 100644 index 00000000000..ce39da5e069 --- /dev/null +++ b/compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.txt @@ -0,0 +1,6 @@ +package + +public fun almostAlwaysTrue(): kotlin.Boolean +public fun test1(): kotlin.Unit +public fun test2(): kotlin.Unit +public fun test3(): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index f9cb68aaf1c..046fc232ca2 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -16268,6 +16268,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/localLateinit.kt"); doTest(fileName); } + + @TestMetadata("uninitialized.kt") + public void testUninitialized() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.kt"); + doTest(fileName); + } } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/PropertyDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/PropertyDescriptor.java index 2e967804b0f..15d88110893 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/PropertyDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/PropertyDescriptor.java @@ -57,8 +57,6 @@ public interface PropertyDescriptor extends VariableDescriptorWithAccessors, Cal @Override PropertyDescriptor substitute(@NotNull TypeSubstitutor substitutor); - boolean isLateInit(); - @NotNull @Override CopyBuilder newCopyBuilder(); diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ValueParameterDescriptor.kt b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ValueParameterDescriptor.kt index 42732d4d465..8d02d6b865a 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/ValueParameterDescriptor.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/ValueParameterDescriptor.kt @@ -54,4 +54,6 @@ interface ValueParameterDescriptor : VariableDescriptor, ParameterDescriptor { val isCrossinline: Boolean val isNoinline: Boolean + + override fun isLateInit(): Boolean = false } diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/VariableDescriptor.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/VariableDescriptor.java index af9f904789b..a809993f42b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/VariableDescriptor.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/VariableDescriptor.java @@ -36,4 +36,6 @@ public interface VariableDescriptor extends ValueDescriptor { * It completely does not means that if isConst then `getCompileTimeInitializer` is not null */ boolean isConst(); + + boolean isLateInit(); } diff --git a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java index f7bafa508c4..8c516ce6c43 100644 --- a/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java +++ b/js/js.translator/src/org/jetbrains/kotlin/js/translate/context/TranslationContext.java @@ -121,8 +121,6 @@ public class TranslationContext { Annotations.Companion.getEMPTY(), Name.identifier("continuation"), continuationDescriptor.getDefaultType(), - /* mutable = */ false, - /* delegated = */ false, SourceElement.NO_SOURCE); } }