Resolve lateinit variables
Do not report UNINITIALIZED_VARIABLE on lateinit variables Provide delegating constructors for descriptors for compatibility.
This commit is contained in:
-2
@@ -396,8 +396,6 @@ class CodegenAnnotatingVisitor extends KtVisitorVoid {
|
|||||||
Annotations.Companion.getEMPTY(),
|
Annotations.Companion.getEMPTY(),
|
||||||
Name.identifier(variableDescriptor.getName().asString() + "$metadata"),
|
Name.identifier(variableDescriptor.getName().asString() + "$metadata"),
|
||||||
ReflectionTypes.Companion.createKPropertyStarType(DescriptorUtilsKt.getModule(variableDescriptor)),
|
ReflectionTypes.Companion.createKPropertyStarType(DescriptorUtilsKt.getModule(variableDescriptor)),
|
||||||
false,
|
|
||||||
false,
|
|
||||||
SourceElement.NO_SOURCE
|
SourceElement.NO_SOURCE
|
||||||
);
|
);
|
||||||
bindingTrace.record(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor, metadataVariableDescriptor);
|
bindingTrace.record(LOCAL_VARIABLE_PROPERTY_METADATA, variableDescriptor, metadataVariableDescriptor);
|
||||||
|
|||||||
@@ -354,7 +354,9 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is VariableDescriptor ->
|
is VariableDescriptor ->
|
||||||
report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt)
|
if (!variableDescriptor.isLateInit) {
|
||||||
|
report(Errors.UNINITIALIZED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.types.TypeSubstitutor;
|
|||||||
|
|
||||||
public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl implements VariableDescriptorWithAccessors {
|
public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl implements VariableDescriptorWithAccessors {
|
||||||
private final boolean isDelegated;
|
private final boolean isDelegated;
|
||||||
|
private final boolean isLateInit;
|
||||||
private LocalVariableAccessorDescriptor.Getter getter;
|
private LocalVariableAccessorDescriptor.Getter getter;
|
||||||
private LocalVariableAccessorDescriptor.Setter setter;
|
private LocalVariableAccessorDescriptor.Setter setter;
|
||||||
|
|
||||||
@@ -36,10 +37,34 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm
|
|||||||
@Nullable KotlinType type,
|
@Nullable KotlinType type,
|
||||||
boolean mutable,
|
boolean mutable,
|
||||||
boolean isDelegated,
|
boolean isDelegated,
|
||||||
|
boolean isLateInit,
|
||||||
@NotNull SourceElement source
|
@NotNull SourceElement source
|
||||||
) {
|
) {
|
||||||
super(containingDeclaration, annotations, name, type, mutable, source);
|
super(containingDeclaration, annotations, name, type, mutable, source);
|
||||||
this.isDelegated = isDelegated;
|
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
|
@Override
|
||||||
@@ -89,4 +114,9 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm
|
|||||||
public boolean isDelegated() {
|
public boolean isDelegated() {
|
||||||
return isDelegated;
|
return isDelegated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLateInit() {
|
||||||
|
return isLateInit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -29,7 +29,8 @@ class SyntheticFieldDescriptor private constructor(
|
|||||||
accessorDescriptor: PropertyAccessorDescriptor,
|
accessorDescriptor: PropertyAccessorDescriptor,
|
||||||
property: KtProperty
|
property: KtProperty
|
||||||
): LocalVariableDescriptor(accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME,
|
): LocalVariableDescriptor(accessorDescriptor, Annotations.EMPTY, SyntheticFieldDescriptor.NAME,
|
||||||
propertyDescriptor.type, propertyDescriptor.isVar, false, property.toSourceElement()) {
|
propertyDescriptor.type, propertyDescriptor.isVar, false, false,
|
||||||
|
property.toSourceElement()) {
|
||||||
|
|
||||||
constructor(accessorDescriptor: PropertyAccessorDescriptor,
|
constructor(accessorDescriptor: PropertyAccessorDescriptor,
|
||||||
property: KtProperty): this(accessorDescriptor.correspondingProperty, accessorDescriptor, property)
|
property: KtProperty): this(accessorDescriptor.correspondingProperty, accessorDescriptor, property)
|
||||||
|
|||||||
@@ -675,8 +675,6 @@ public class DescriptorResolver {
|
|||||||
annotationResolver.resolveAnnotationsWithArguments(scope, parameter.getModifierList(), trace),
|
annotationResolver.resolveAnnotationsWithArguments(scope, parameter.getModifierList(), trace),
|
||||||
KtPsiUtil.safeName(parameter.getName()),
|
KtPsiUtil.safeName(parameter.getName()),
|
||||||
approximatedType,
|
approximatedType,
|
||||||
false,
|
|
||||||
false,
|
|
||||||
KotlinSourceElementKt.toSourceElement(parameter)
|
KotlinSourceElementKt.toSourceElement(parameter)
|
||||||
);
|
);
|
||||||
trace.record(BindingContext.VALUE_PARAMETER, parameter, variableDescriptor);
|
trace.record(BindingContext.VALUE_PARAMETER, parameter, variableDescriptor);
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.descriptors.*
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
import org.jetbrains.kotlin.descriptors.impl.*
|
import org.jetbrains.kotlin.descriptors.impl.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors.*
|
import org.jetbrains.kotlin.diagnostics.Errors.*
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.KtProperty
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
import org.jetbrains.kotlin.psi.KtPsiUtil
|
import org.jetbrains.kotlin.psi.KtPsiUtil
|
||||||
@@ -195,6 +196,7 @@ class LocalVariableResolver(
|
|||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): LocalVariableDescriptor {
|
): LocalVariableDescriptor {
|
||||||
val hasDelegate = variable is KtProperty && variable.hasDelegate()
|
val hasDelegate = variable is KtProperty && variable.hasDelegate()
|
||||||
|
val hasLateinit = variable.hasModifier(KtTokens.LATEINIT_KEYWORD)
|
||||||
val variableDescriptor = LocalVariableDescriptor(
|
val variableDescriptor = LocalVariableDescriptor(
|
||||||
scope.ownerDescriptor,
|
scope.ownerDescriptor,
|
||||||
annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace),
|
annotationResolver.resolveAnnotationsWithArguments(scope, variable.modifierList, trace),
|
||||||
@@ -207,6 +209,7 @@ class LocalVariableResolver(
|
|||||||
type,
|
type,
|
||||||
variable.isVar,
|
variable.isVar,
|
||||||
hasDelegate,
|
hasDelegate,
|
||||||
|
hasLateinit,
|
||||||
variable.toSourceElement()
|
variable.toSourceElement()
|
||||||
)
|
)
|
||||||
trace.record(BindingContext.VARIABLE, variable, variableDescriptor)
|
trace.record(BindingContext.VARIABLE, variable, variableDescriptor)
|
||||||
|
|||||||
@@ -275,6 +275,8 @@ class TypeResolver(
|
|||||||
|
|
||||||
override fun isVar() = false
|
override fun isVar() = false
|
||||||
|
|
||||||
|
override fun isLateInit() = false
|
||||||
|
|
||||||
override fun getCompileTimeInitializer() = null
|
override fun getCompileTimeInitializer() = null
|
||||||
|
|
||||||
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R {
|
override fun <R : Any?, D : Any?> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R {
|
||||||
|
|||||||
+2
-2
@@ -592,8 +592,8 @@ class DoubleColonExpressionResolver(
|
|||||||
|
|
||||||
internal fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) {
|
internal fun bindPropertyReference(expression: KtCallableReferenceExpression, referenceType: KotlinType, context: ResolutionContext<*>) {
|
||||||
val localVariable = LocalVariableDescriptor(
|
val localVariable = LocalVariableDescriptor(
|
||||||
context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType, /* mutable = */ false,
|
context.scope.ownerDescriptor, Annotations.EMPTY, Name.special("<anonymous>"), referenceType,
|
||||||
/* isDelegated = */ false, expression.toSourceElement()
|
expression.toSourceElement()
|
||||||
)
|
)
|
||||||
|
|
||||||
context.trace.record(BindingContext.VARIABLE, expression, localVariable)
|
context.trace.record(BindingContext.VARIABLE, expression, localVariable)
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ class JvmSharedVariablesManager(val builtIns: KotlinBuiltIns) : SharedVariablesM
|
|||||||
LocalVariableDescriptor(
|
LocalVariableDescriptor(
|
||||||
variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name,
|
variableDescriptor.containingDeclaration, variableDescriptor.annotations, variableDescriptor.name,
|
||||||
getSharedVariableType(variableDescriptor.type),
|
getSharedVariableType(variableDescriptor.type),
|
||||||
false, false, variableDescriptor.source
|
false, false, variableDescriptor.isLateInit, variableDescriptor.source
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement {
|
override fun defineSharedValue(sharedVariableDescriptor: VariableDescriptor, originalDeclaration: IrVariable): IrStatement {
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ class IrLocalDelegatedPropertyDelegateDescriptorImpl(
|
|||||||
|
|
||||||
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
|
override fun getCompileTimeInitializer(): ConstantValue<*>? = null
|
||||||
override fun isVar(): Boolean = false
|
override fun isVar(): Boolean = false
|
||||||
|
override fun isLateInit(): Boolean = false
|
||||||
override fun substitute(substitutor: TypeSubstitutor): VariableDescriptor? = throw UnsupportedOperationException()
|
override fun substitute(substitutor: TypeSubstitutor): VariableDescriptor? = throw UnsupportedOperationException()
|
||||||
override fun getVisibility(): Visibility = Visibilities.LOCAL
|
override fun getVisibility(): Visibility = Visibilities.LOCAL
|
||||||
|
|
||||||
|
|||||||
+2
@@ -44,6 +44,8 @@ class IrTemporaryVariableDescriptorImpl(
|
|||||||
|
|
||||||
override fun isVar(): Boolean = isMutable
|
override fun isVar(): Boolean = isMutable
|
||||||
|
|
||||||
|
override fun isLateInit(): Boolean = false
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>, data: D): R =
|
||||||
visitor.visitVariableDescriptor(this, data)
|
visitor.visitVariableDescriptor(this, data)
|
||||||
}
|
}
|
||||||
+2
@@ -67,6 +67,8 @@ open class FakeCallableDescriptorForObject(
|
|||||||
|
|
||||||
override fun isConst(): Boolean = false
|
override fun isConst(): Boolean = false
|
||||||
|
|
||||||
|
override fun isLateInit(): Boolean = false
|
||||||
|
|
||||||
override fun equals(other: Any?) = other is FakeCallableDescriptorForObject && classDescriptor == other.classDescriptor
|
override fun equals(other: Any?) = other is FakeCallableDescriptorForObject && classDescriptor == other.classDescriptor
|
||||||
|
|
||||||
override fun hashCode() = classDescriptor.hashCode()
|
override fun hashCode() = classDescriptor.hashCode()
|
||||||
|
|||||||
+22
@@ -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
|
||||||
|
}
|
||||||
+6
@@ -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
|
||||||
@@ -16268,6 +16268,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/localLateinit.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/localLateinit.kt");
|
||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("uninitialized.kt")
|
||||||
|
public void testUninitialized() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/properties/localLateinit/uninitialized.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ public interface PropertyDescriptor extends VariableDescriptorWithAccessors, Cal
|
|||||||
@Override
|
@Override
|
||||||
PropertyDescriptor substitute(@NotNull TypeSubstitutor substitutor);
|
PropertyDescriptor substitute(@NotNull TypeSubstitutor substitutor);
|
||||||
|
|
||||||
boolean isLateInit();
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
CopyBuilder<? extends PropertyDescriptor> newCopyBuilder();
|
CopyBuilder<? extends PropertyDescriptor> newCopyBuilder();
|
||||||
|
|||||||
@@ -54,4 +54,6 @@ interface ValueParameterDescriptor : VariableDescriptor, ParameterDescriptor {
|
|||||||
val isCrossinline: Boolean
|
val isCrossinline: Boolean
|
||||||
|
|
||||||
val isNoinline: Boolean
|
val isNoinline: Boolean
|
||||||
|
|
||||||
|
override fun isLateInit(): Boolean = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,4 +36,6 @@ public interface VariableDescriptor extends ValueDescriptor {
|
|||||||
* It completely does not means that if isConst then `getCompileTimeInitializer` is not null
|
* It completely does not means that if isConst then `getCompileTimeInitializer` is not null
|
||||||
*/
|
*/
|
||||||
boolean isConst();
|
boolean isConst();
|
||||||
|
|
||||||
|
boolean isLateInit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,8 +121,6 @@ public class TranslationContext {
|
|||||||
Annotations.Companion.getEMPTY(),
|
Annotations.Companion.getEMPTY(),
|
||||||
Name.identifier("continuation"),
|
Name.identifier("continuation"),
|
||||||
continuationDescriptor.getDefaultType(),
|
continuationDescriptor.getDefaultType(),
|
||||||
/* mutable = */ false,
|
|
||||||
/* delegated = */ false,
|
|
||||||
SourceElement.NO_SOURCE);
|
SourceElement.NO_SOURCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user