Delegated properties now cannot be used before initialization #KT-10869 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-02-01 19:06:59 +03:00
parent 65f754ffca
commit 45298e0bad
10 changed files with 95 additions and 21 deletions
@@ -360,6 +360,14 @@ public class ControlFlowInformationProvider {
}
}
private boolean isDefinitelyInitialized(@NotNull PropertyDescriptor propertyDescriptor) {
if (propertyDescriptor.isLateInit()) return true;
if (trace.get(BACKING_FIELD_REQUIRED, propertyDescriptor) == Boolean.TRUE) return false;
PsiElement property = DescriptorToSourceUtils.descriptorToDeclaration(propertyDescriptor);
if (property instanceof KtProperty && ((KtProperty) property).hasDelegate()) return false;
return true;
}
private void checkIsInitialized(
@NotNull VariableInitContext ctxt,
@NotNull KtElement element,
@@ -370,11 +378,8 @@ public class ControlFlowInformationProvider {
boolean isDefinitelyInitialized = ctxt.exitInitState.definitelyInitialized();
VariableDescriptor variableDescriptor = ctxt.variableDescriptor;
if (variableDescriptor instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variableDescriptor;
if (propertyDescriptor.isLateInit() || !trace.get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)) {
isDefinitelyInitialized = true;
}
if (!isDefinitelyInitialized && variableDescriptor instanceof PropertyDescriptor) {
isDefinitelyInitialized = isDefinitelyInitialized((PropertyDescriptor) variableDescriptor);
}
if (!isDefinitelyInitialized && !varWithUninitializedErrorGenerated.contains(variableDescriptor)) {
if (!(variableDescriptor instanceof PropertyDescriptor)) {
@@ -1001,6 +1001,8 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
}
val delegate = property.delegateExpression
if (delegate != null) {
// We do not want to have getDeferredValue(delegate) here, because delegate value will be read anyway later
visitAssignment(property, getDeferredValue(null), property)
generateInstructions(delegate)
if (builder.getBoundValue(delegate) != null) {
createSyntheticValue(property, MagicKind.VALUE_CONSUMER, delegate)
@@ -54,12 +54,14 @@ val b by a
L0:
1 <START>
v(val b by a)
r(a) -> <v0>
magic[VALUE_CONSUMER](val b by a|<v0>) -> <v1>
magic[UNRECOGNIZED_WRITE_RHS](val b by a) -> <v0>
w(b|<v0>)
r(a) -> <v1>
magic[VALUE_CONSUMER](val b by a|<v1>) -> <v2>
L1:
<END> NEXT:[<SINK>]
<END> NEXT:[<SINK>]
error:
<ERROR> PREV:[]
<ERROR> PREV:[]
sink:
<SINK> PREV:[<ERROR>, <END>]
<SINK> PREV:[<ERROR>, <END>]
=====================
@@ -19,6 +19,7 @@ Delegate() <v0>: Delegate NEW: call(Delegate(), <init>) -> <v0>
== b ==
val b by a
---------------------
<v1>: * NEW: magic[VALUE_CONSUMER](val b by a|<v0>) -> <v1>
a <v0>: Delegate NEW: r(a) -> <v0>
<v0>: Int NEW: magic[UNRECOGNIZED_WRITE_RHS](val b by a) -> <v0>
<v2>: * NEW: magic[VALUE_CONSUMER](val b by a|<v1>) -> <v2>
a <v1>: Delegate NEW: r(a) -> <v1>
=====================
@@ -4,14 +4,16 @@ val foo: Int by throw NullPointerException()
L0:
1 <START>
v(val foo: Int by throw NullPointerException())
magic[UNRECOGNIZED_WRITE_RHS](val foo: Int by throw NullPointerException()) -> <v0>
w(foo|<v0>)
mark(throw NullPointerException())
mark(NullPointerException())
call(NullPointerException(), <init>) -> <v0>
throw (throw NullPointerException()|<v0>) NEXT:[<ERROR>]
call(NullPointerException(), <init>) -> <v1>
throw (throw NullPointerException()|<v1>) NEXT:[<ERROR>]
L1:
<END> NEXT:[<SINK>] PREV:[]
<END> NEXT:[<SINK>] PREV:[]
error:
<ERROR> PREV:[throw (throw NullPointerException()|<v0>)]
<ERROR> PREV:[throw (throw NullPointerException()|<v1>)]
sink:
<SINK> PREV:[<ERROR>, <END>]
=====================
<SINK> PREV:[<ERROR>, <END>]
=====================
@@ -1,5 +1,6 @@
== foo ==
val foo: Int by throw NullPointerException()
---------------------
NullPointerException() <v0>: {<: Throwable} NEW: call(NullPointerException(), <init>) -> <v0>
=====================
<v0>: Int NEW: magic[UNRECOGNIZED_WRITE_RHS](val foo: Int by throw NullPointerException()) -> <v0>
NullPointerException() <v1>: {<: Throwable} NEW: call(NullPointerException(), <init>) -> <v1>
=====================
@@ -0,0 +1,32 @@
// See also KT-10869: Accessing lazy properties from init causes IllegalArgumentException
import kotlin.reflect.KProperty
class CustomDelegate {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
}
class Kaboom() {
// Here and below we should have errors for simple AND delegated
init {
<!UNINITIALIZED_VARIABLE!>delegated<!>.hashCode()
<!UNINITIALIZED_VARIABLE!>simple<!>.hashCode()
withGetter.hashCode()
}
val other = <!UNINITIALIZED_VARIABLE!>delegated<!>
val another = <!UNINITIALIZED_VARIABLE!>simple<!>
val something = withGetter
val delegated: String by CustomDelegate()
val simple = "xyz"
val withGetter: String
get() = "abc"
// No error should be here
val after = delegated
}
@@ -0,0 +1,23 @@
package
public final class CustomDelegate {
public constructor CustomDelegate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ prop: kotlin.reflect.KProperty<*>): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class Kaboom {
public constructor Kaboom()
public final val after: kotlin.String
public final val another: kotlin.String = "xyz"
public final val delegated: kotlin.String
public final val other: kotlin.String
public final val simple: kotlin.String = "xyz"
public final val something: kotlin.String
public final val withGetter: kotlin.String
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -6,7 +6,7 @@ val a by <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>a<!>
val b by Delegate(<!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>b<!>)
val c by <!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>d<!>
val c by <!UNINITIALIZED_VARIABLE, DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>d<!>
val d by <!TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM!>c<!>
class Delegate(i: Int) {
@@ -2853,6 +2853,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("delegatedPropertyEarlyAccess.kt")
public void testDelegatedPropertyEarlyAccess() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/delegatedPropertyEarlyAccess.kt");
doTest(fileName);
}
@TestMetadata("elvisNotProcessed.kt")
public void testElvisNotProcessed() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/controlFlowAnalysis/elvisNotProcessed.kt");