K2: Fix ISE from inference on delegate vars with implicit types
See the test data. ISE happened because at some point after incomplete `getValue` resolution of `a` property, we updated in the `transformAccessors` the property type to the `Variable(Y)` type and then used it as a 3rd argument for `setValue` call which is incorrect because the variable belongs to a different constraint system (from `getValue`). Mostly, the fix is just a repeating K1 behavior, namely postponing `setValue` resolution until delegate inference is completed. ^KT-59066 Fixed
This commit is contained in:
committed by
Space Team
parent
b8c4a4c80a
commit
41933facbb
+12
@@ -8974,12 +8974,24 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noInferenceFromGetValueThroughSetValue.kt")
|
||||||
|
public void testNoInferenceFromGetValueThroughSetValue() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromGetValueThroughSetValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
||||||
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noPreliminarySetterInferenceForImplicitlyTypedVar.kt")
|
||||||
|
public void testNoPreliminarySetterInferenceForImplicitlyTypedVar() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noPreliminarySetterInferenceForImplicitlyTypedVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonDefaultAccessors.kt")
|
@TestMetadata("nonDefaultAccessors.kt")
|
||||||
public void testNonDefaultAccessors() throws Exception {
|
public void testNonDefaultAccessors() throws Exception {
|
||||||
|
|||||||
+12
@@ -8974,12 +8974,24 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noInferenceFromGetValueThroughSetValue.kt")
|
||||||
|
public void testNoInferenceFromGetValueThroughSetValue() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromGetValueThroughSetValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
||||||
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noPreliminarySetterInferenceForImplicitlyTypedVar.kt")
|
||||||
|
public void testNoPreliminarySetterInferenceForImplicitlyTypedVar() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noPreliminarySetterInferenceForImplicitlyTypedVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonDefaultAccessors.kt")
|
@TestMetadata("nonDefaultAccessors.kt")
|
||||||
public void testNonDefaultAccessors() throws Exception {
|
public void testNonDefaultAccessors() throws Exception {
|
||||||
|
|||||||
+12
@@ -8974,12 +8974,24 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noInferenceFromGetValueThroughSetValue.kt")
|
||||||
|
public void testNoInferenceFromGetValueThroughSetValue() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromGetValueThroughSetValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
||||||
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noPreliminarySetterInferenceForImplicitlyTypedVar.kt")
|
||||||
|
public void testNoPreliminarySetterInferenceForImplicitlyTypedVar() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noPreliminarySetterInferenceForImplicitlyTypedVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonDefaultAccessors.kt")
|
@TestMetadata("nonDefaultAccessors.kt")
|
||||||
public void testNonDefaultAccessors() throws Exception {
|
public void testNonDefaultAccessors() throws Exception {
|
||||||
|
|||||||
+12
@@ -8980,12 +8980,24 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noInferenceFromGetValueThroughSetValue.kt")
|
||||||
|
public void testNoInferenceFromGetValueThroughSetValue() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromGetValueThroughSetValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
||||||
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noPreliminarySetterInferenceForImplicitlyTypedVar.kt")
|
||||||
|
public void testNoPreliminarySetterInferenceForImplicitlyTypedVar() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noPreliminarySetterInferenceForImplicitlyTypedVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonDefaultAccessors.kt")
|
@TestMetadata("nonDefaultAccessors.kt")
|
||||||
public void testNonDefaultAccessors() throws Exception {
|
public void testNonDefaultAccessors() throws Exception {
|
||||||
|
|||||||
+40
-7
@@ -181,7 +181,9 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
val propertyTypeIsKnown = propertyTypeRefAfterResolve is FirResolvedTypeRef
|
val propertyTypeIsKnown = propertyTypeRefAfterResolve is FirResolvedTypeRef
|
||||||
val mayResolveGetter = mayResolveSetter || !propertyTypeIsKnown
|
val mayResolveGetter = mayResolveSetter || !propertyTypeIsKnown
|
||||||
if (mayResolveGetter) {
|
if (mayResolveGetter) {
|
||||||
property.transformAccessors(mayResolveSetter)
|
property.transformAccessors(
|
||||||
|
if (mayResolveSetter) SetterResolutionMode.FULLY_RESOLVE else SetterResolutionMode.ONLY_IMPLICIT_PARAMETER_TYPE
|
||||||
|
)
|
||||||
property.replaceBodyResolveState(
|
property.replaceBodyResolveState(
|
||||||
if (mayResolveSetter) FirPropertyBodyResolveState.EVERYTHING_RESOLVED
|
if (mayResolveSetter) FirPropertyBodyResolveState.EVERYTHING_RESOLVED
|
||||||
else FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED
|
else FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED
|
||||||
@@ -277,6 +279,8 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun transformPropertyAccessorsWithDelegate(property: FirProperty, delegate: FirExpression) {
|
private fun transformPropertyAccessorsWithDelegate(property: FirProperty, delegate: FirExpression) {
|
||||||
|
val isImplicitTypedProperty = property.returnTypeRef is FirImplicitTypeRef
|
||||||
|
|
||||||
context.forPropertyDelegateAccessors(property, resolutionContext, callCompleter) {
|
context.forPropertyDelegateAccessors(property, resolutionContext, callCompleter) {
|
||||||
dataFlowAnalyzer.enterDelegateExpression()
|
dataFlowAnalyzer.enterDelegateExpression()
|
||||||
// Resolve delegate expression, after that, delegate will contain either expr.provideDelegate or expr
|
// Resolve delegate expression, after that, delegate will contain either expr.provideDelegate or expr
|
||||||
@@ -288,7 +292,12 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property.transformAccessors()
|
// We don't use inference from setValue calls (i.e. don't resolve setters until the delegate inference is completed),
|
||||||
|
// when property doesn't have explicit type.
|
||||||
|
// It's necessary because we need to supply the property type as the 3rd argument for `setValue` and there might be uninferred
|
||||||
|
// variables from `getValue`.
|
||||||
|
// The same logic was used at K1 (see org.jetbrains.kotlin.resolve.DelegatedPropertyResolver.inferDelegateTypeFromGetSetValueMethods)
|
||||||
|
property.transformAccessors(if (isImplicitTypedProperty) SetterResolutionMode.SKIP else SetterResolutionMode.FULLY_RESOLVE)
|
||||||
val completedCalls = completeCandidates()
|
val completedCalls = completeCandidates()
|
||||||
|
|
||||||
val finalSubstitutor = createFinalSubstitutor()
|
val finalSubstitutor = createFinalSubstitutor()
|
||||||
@@ -310,10 +319,14 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
completedCalls.forEach {
|
completedCalls.forEach {
|
||||||
it.transformSingle(callCompletionResultsWriter, null)
|
it.transformSingle(callCompletionResultsWriter, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
dataFlowAnalyzer.exitDelegateExpression(delegate)
|
|
||||||
property
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `isImplicitTypedProperty` means we haven't run setter resolution yet (see its second usage)
|
||||||
|
if (isImplicitTypedProperty) {
|
||||||
|
property.resolveSetter(property.returnTypeRef, mayResolveSetterBody = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
dataFlowAnalyzer.exitDelegateExpression(delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transformPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: ResolutionMode): FirStatement {
|
override fun transformPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: ResolutionMode): FirStatement {
|
||||||
@@ -420,7 +433,17 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
return variable
|
return variable
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirProperty.transformAccessors(mayResolveSetter: Boolean = true) {
|
// TODO: This enum might actually be a boolean (resolve setter/don't resolve setter)
|
||||||
|
// But for some reason, in IDE there's a need to resolve setter's parameter types on the implicit-resolution stage
|
||||||
|
// See ad183434137939a0c9eeea2f7df9ef522672a18e commit.
|
||||||
|
// But for delegate inference case, we don't need both body of the setter and its parameter resolved (SKIP mode)
|
||||||
|
private enum class SetterResolutionMode {
|
||||||
|
FULLY_RESOLVE, ONLY_IMPLICIT_PARAMETER_TYPE, SKIP
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirProperty.transformAccessors(
|
||||||
|
setterResolutionMode: SetterResolutionMode = SetterResolutionMode.FULLY_RESOLVE
|
||||||
|
) {
|
||||||
var enhancedTypeRef = returnTypeRef
|
var enhancedTypeRef = returnTypeRef
|
||||||
if (bodyResolveState < FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED) {
|
if (bodyResolveState < FirPropertyBodyResolveState.INITIALIZER_AND_GETTER_RESOLVED) {
|
||||||
getter?.let {
|
getter?.let {
|
||||||
@@ -433,10 +456,20 @@ open class FirDeclarationsResolveTransformer(
|
|||||||
// We need update type of getter for case when its type was approximated
|
// We need update type of getter for case when its type was approximated
|
||||||
getter?.transformTypeWithPropertyType(enhancedTypeRef, forceUpdateForNonImplicitTypes = true)
|
getter?.transformTypeWithPropertyType(enhancedTypeRef, forceUpdateForNonImplicitTypes = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (setterResolutionMode != SetterResolutionMode.SKIP) {
|
||||||
|
resolveSetter(enhancedTypeRef, mayResolveSetterBody = setterResolutionMode == SetterResolutionMode.FULLY_RESOLVE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun FirProperty.resolveSetter(
|
||||||
|
enhancedTypeRef: FirTypeRef,
|
||||||
|
mayResolveSetterBody: Boolean,
|
||||||
|
) {
|
||||||
setter?.let {
|
setter?.let {
|
||||||
it.transformTypeWithPropertyType(enhancedTypeRef)
|
it.transformTypeWithPropertyType(enhancedTypeRef)
|
||||||
|
|
||||||
if (mayResolveSetter) {
|
if (mayResolveSetterBody) {
|
||||||
transformAccessor(it, enhancedTypeRef, this)
|
transformAccessor(it, enhancedTypeRef, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+24
@@ -0,0 +1,24 @@
|
|||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
// Definitions
|
||||||
|
class M<E>
|
||||||
|
|
||||||
|
operator fun <X> M<out X>.getValue(thisRef: Any?, property: KProperty<*>): String = "value"
|
||||||
|
operator fun <Z> M<in Z>.setValue(thisRef: Any?, property: KProperty<*>, value: Z) {}
|
||||||
|
|
||||||
|
fun <U> m(): M<U> = M()
|
||||||
|
|
||||||
|
// We don't allow to infer type of a delegate expression through a setValue, where the argument (value) is constrained by the return type of a getValue
|
||||||
|
var a by <!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>m<!>()
|
||||||
|
|
||||||
|
// We infer type of delegate expression through a setValue from the explicit property type
|
||||||
|
var b: String by m()
|
||||||
|
|
||||||
|
fun takeString(v: String) {}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
takeString(a)
|
||||||
|
a = "a"
|
||||||
|
takeString(b)
|
||||||
|
b = "b"
|
||||||
|
}
|
||||||
Vendored
+24
@@ -0,0 +1,24 @@
|
|||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
// Definitions
|
||||||
|
class M<E>
|
||||||
|
|
||||||
|
operator fun <X> M<out X>.getValue(thisRef: Any?, property: KProperty<*>): String = "value"
|
||||||
|
operator fun <Z> M<in Z>.setValue(thisRef: Any?, property: KProperty<*>, value: Z) {}
|
||||||
|
|
||||||
|
fun <U> m(): M<U> = M()
|
||||||
|
|
||||||
|
// We don't allow to infer type of a delegate expression through a setValue, where the argument (value) is constrained by the return type of a getValue
|
||||||
|
var a by <!DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE, DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE!><!NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>m<!>()<!>
|
||||||
|
|
||||||
|
// We infer type of delegate expression through a setValue from the explicit property type
|
||||||
|
var b: String by m()
|
||||||
|
|
||||||
|
fun takeString(v: String) {}
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
takeString(<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!>)
|
||||||
|
<!DEBUG_INFO_ELEMENT_WITH_ERROR_TYPE!>a<!> = "a"
|
||||||
|
takeString(b)
|
||||||
|
b = "b"
|
||||||
|
}
|
||||||
+27
@@ -0,0 +1,27 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// WITH_STDLIB
|
||||||
|
// WITH_REFLECT
|
||||||
|
// ISSUE: KT-59066
|
||||||
|
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
interface M< E>
|
||||||
|
|
||||||
|
public operator fun <X, Y : X> M<out X>.getValue(thisRef: Any?, property: KProperty<*>): Y =
|
||||||
|
TODO()
|
||||||
|
|
||||||
|
public operator fun <Z> M<in Z>.setValue(thisRef: Any?, property: KProperty<*>, value: Z) {}
|
||||||
|
|
||||||
|
fun <U> m(u: U): M<U> = TODO()
|
||||||
|
|
||||||
|
var a by m("")
|
||||||
|
|
||||||
|
var b by mutableMapOf("" to 1)
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
a.length
|
||||||
|
a = "b"
|
||||||
|
|
||||||
|
b = 23
|
||||||
|
b.and(4)
|
||||||
|
}
|
||||||
Generated
+12
@@ -8980,12 +8980,24 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/missedSetter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noInferenceFromGetValueThroughSetValue.kt")
|
||||||
|
public void testNoInferenceFromGetValueThroughSetValue() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromGetValueThroughSetValue.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
@TestMetadata("noInferenceFromWrappedDelegate.kt")
|
||||||
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
public void testNoInferenceFromWrappedDelegate() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noInferenceFromWrappedDelegate.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("noPreliminarySetterInferenceForImplicitlyTypedVar.kt")
|
||||||
|
public void testNoPreliminarySetterInferenceForImplicitlyTypedVar() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/delegatedProperty/noPreliminarySetterInferenceForImplicitlyTypedVar.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("nonDefaultAccessors.kt")
|
@TestMetadata("nonDefaultAccessors.kt")
|
||||||
public void testNonDefaultAccessors() throws Exception {
|
public void testNonDefaultAccessors() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user