diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java index 2cb316040be..0cf3c6fbe18 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirOldFrontendDiagnosticsTestGenerated.java @@ -6131,6 +6131,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt"); } + @TestMetadata("provideDelegateResolutionWithStubTypes.kt") + public void testProvideDelegateResolutionWithStubTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); + } + @TestMetadata("setValue.kt") public void testSetValue() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt"); diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index f4d69fff08a..2658063788b 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -9527,6 +9527,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/generic.kt"); } + @TestMetadata("genericDelegateWithNoAdditionalInfo.kt") + public void testGenericDelegateWithNoAdditionalInfo() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt"); + } + @TestMetadata("hostCheck.kt") public void testHostCheck() throws Exception { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/hostCheck.kt"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyInferenceSession.kt index 56a6ff7a16c..ea51ef37666 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyInferenceSession.kt @@ -90,17 +90,9 @@ class DelegatedPropertyInferenceSession( override fun shouldCompleteResolvedSubAtomsOf(resolvedCallAtom: ResolvedCallAtom) = true } -object InferenceSessionForExistingCandidates : InferenceSession { +class InferenceSessionForExistingCandidates(private val resolveReceiverIndependently: Boolean) : InferenceSession { override fun shouldRunCompletion(candidate: KotlinResolutionCandidate): Boolean { - if (ErrorUtils.isError(candidate.resolvedCall.candidateDescriptor)) return false - - val builder = candidate.getSystem().getBuilder() - for ((_, variable) in builder.currentStorage().notFixedTypeVariables) { - val hasProperConstraint = variable.constraints.any { candidate.getSystem().getBuilder().isProperType(it.type) } - if (hasProperConstraint) return true - } - - return false + return !ErrorUtils.isError(candidate.resolvedCall.candidateDescriptor) } override fun addPartialCallInfo(callInfo: PartialCallInfo) {} @@ -122,18 +114,7 @@ object InferenceSessionForExistingCandidates : InferenceSession { override fun computeCompletionMode( candidate: KotlinResolutionCandidate - ): KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode? { - // this is a hack to mitigate questionable behavior in delegated properties design, namely: - // see test DelegatedProperty.ProvideDelegate#testHostAndReceiver2 + ): KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode? = null - // Normally, provideDelegate should be analyzed in INDEPENDENT mode, but now in OI there is one corner case, which - // doesn't fit into this design - val builder = candidate.getSystem().getBuilder() - for ((_, variable) in builder.currentStorage().notFixedTypeVariables) { - val hasProperConstraint = variable.constraints.any { candidate.getSystem().getBuilder().isProperType(it.type) } - if (hasProperConstraint) return null - } - - return KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode.PARTIAL - } + override fun resolveReceiverIndependently(): Boolean = resolveReceiverIndependently } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt index da767087761..cfca639bfa5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.kt @@ -26,7 +26,9 @@ import org.jetbrains.kotlin.resolve.calls.components.PostponedArgumentsAnalyzer import org.jetbrains.kotlin.resolve.calls.context.ContextDependency import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.components.EmptySubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.KotlinConstraintSystemCompleter +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.FROM_COMPLETER import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor import org.jetbrains.kotlin.resolve.calls.inference.toHandle @@ -45,6 +47,7 @@ import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE import org.jetbrains.kotlin.types.TypeUtils.noExpectedType import org.jetbrains.kotlin.types.checker.KotlinTypeChecker +import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.createFakeExpressionOfType @@ -549,20 +552,35 @@ class DelegatedPropertyResolver( delegateType = delegateTypeConstructor.getApproximatedType() if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorProvideDelegate)) { + val traceForProvideDelegate = TemporaryBindingTrace.create(traceToResolveDelegatedProperty, "Trace to resolve provide delegate") + + val substitutionMap: Map? = buildSubstitutionMapOfNonFixedVariables(delegateType) + val nonFixedVariablesToStubTypesSubstitutor = + if (substitutionMap != null) + NewTypeSubstitutorByConstructorMap(substitutionMap.mapKeys { it.key.constructor }) + else + EmptySubstitutor + + val delegateTypeWithoutNonFixedVariables = nonFixedVariablesToStubTypesSubstitutor.safeSubstitute(delegateType.unwrap()) + val contextForProvideDelegate = createContextForProvideDelegateMethod( - scopeForDelegate, delegateDataFlow, traceToResolveDelegatedProperty, InferenceSessionForExistingCandidates + scopeForDelegate, delegateDataFlow, traceForProvideDelegate, InferenceSessionForExistingCandidates(substitutionMap != null) ) + val provideDelegateResults = getProvideDelegateMethod( - variableDescriptor, delegateExpression, delegateType, contextForProvideDelegate + variableDescriptor, delegateExpression, delegateTypeWithoutNonFixedVariables, contextForProvideDelegate ) if (conventionMethodFound(provideDelegateResults)) { val provideDelegateDescriptor = provideDelegateResults.resultingDescriptor if (provideDelegateDescriptor.isOperator) { - delegateType = provideDelegateDescriptor.returnType ?: return null + delegateType = inverseSubstitution(provideDelegateDescriptor.returnType, substitutionMap) ?: return null delegateDataFlow = provideDelegateResults.resultingCall.dataFlowInfoForArguments.resultInfo } - trace.record(PROVIDE_DELEGATE_RESOLVED_CALL, variableDescriptor, provideDelegateResults.resultingCall) + if (substitutionMap == null) { + traceForProvideDelegate.record(PROVIDE_DELEGATE_RESOLVED_CALL, variableDescriptor, provideDelegateResults.resultingCall) + traceForProvideDelegate.commit() // otherwise we have to reanalyze provideDelegate with good delegate type + } } } return inferDelegateTypeFromGetSetValueMethods( @@ -570,6 +588,38 @@ class DelegatedPropertyResolver( ) } + private fun inverseSubstitution(type: KotlinType?, substitutionMap: Map?): UnwrappedType? { + if (type == null) return null + if (substitutionMap == null) return type.unwrap() + + val invertedMap = hashMapOf() + for ((variable, stubType) in substitutionMap) { + invertedMap[stubType.constructor] = variable + } + + return NewTypeSubstitutorByConstructorMap(invertedMap).safeSubstitute(type.unwrap()) + } + + private fun buildSubstitutionMapOfNonFixedVariables(type: KotlinType): Map? { + // This is an exception for delegated properties that return just type variable + if (type.constructor is NewTypeVariableConstructor) return null + + var substitutionMap: MutableMap? = null + type.contains { innerType -> + val constructor = innerType.constructor + if (constructor is NewTypeVariableConstructor) { + if (substitutionMap == null) substitutionMap = hashMapOf() + if (innerType !in substitutionMap!!) { + substitutionMap!![innerType] = StubTypeForProvideDelegateReceiver(constructor, innerType.isMarkedNullable) + } + } + + false + } + + return substitutionMap + } + private fun inferDelegateTypeFromGetSetValueMethods( delegateExpression: KtExpression, variableDescriptor: VariableDescriptorWithAccessors, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt index 221a5c1e569..ece60cf7800 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/ManyCandidatesResolver.kt @@ -159,6 +159,8 @@ abstract class ManyCandidatesResolver( override fun computeCompletionMode(candidate: KotlinResolutionCandidate) = null + override fun resolveReceiverIndependently(): Boolean = false + private fun PartialCallInfo.asCallResolutionResult( diagnosticsHolder: KotlinDiagnosticsHolder.SimpleHolder, commonSystem: NewConstraintSystem diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/InferenceSession.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/InferenceSession.kt index 54788e6b43f..fdd44643f4c 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/InferenceSession.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/InferenceSession.kt @@ -31,6 +31,8 @@ interface InferenceSession { override fun computeCompletionMode( candidate: KotlinResolutionCandidate ): KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode? = null + + override fun resolveReceiverIndependently(): Boolean = false } } @@ -49,6 +51,7 @@ interface InferenceSession { fun callCompleted(resolvedAtom: ResolvedAtom): Boolean fun shouldCompleteResolvedSubAtomsOf(resolvedCallAtom: ResolvedCallAtom): Boolean fun computeCompletionMode(candidate: KotlinResolutionCandidate): KotlinConstraintSystemCompleter.ConstraintSystemCompletionMode? + fun resolveReceiverIndependently(): Boolean } interface PartialCallInfo { diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt index 27ffe26da58..bc7a885ee9a 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponeArgumentsChecks.kt @@ -36,9 +36,10 @@ fun resolveKtPrimitive( diagnosticsHolder: KotlinDiagnosticsHolder, receiverInfo: ReceiverInfo, convertedType: UnwrappedType?, + inferenceSession: InferenceSession? ): ResolvedAtom = when (argument) { is SimpleKotlinCallArgument -> - checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo, convertedType) + checkSimpleArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo, convertedType, inferenceSession) is LambdaKotlinCallArgument -> preprocessLambdaArgument(csBuilder, argument, expectedType, diagnosticsHolder) diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt index 17d8ebde48f..dbbcd6abb96 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/PostponedArgumentsAnalyzer.kt @@ -149,7 +149,9 @@ class PostponedArgumentsAnalyzer( val subResolvedKtPrimitives = allReturnArguments.map { resolveKtPrimitive( - c.getBuilder(), it, lambda.returnType.let(::substitute), diagnosticHolder, ReceiverInfo.notReceiver, convertedType = null + c.getBuilder(), it, lambda.returnType.let(::substitute), + diagnosticHolder, ReceiverInfo.notReceiver, convertedType = null, + inferenceSession ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt index e133ab7a461..b203e8ea7a5 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ResolutionParts.kt @@ -439,6 +439,7 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument( } else null + val inferenceSession = resolutionCallbacks.inferenceSession if (candidateExpectedType == null || // Nothing to convert convertedExpectedType != null || // Type is already converted isReceiver || // Receivers don't participate in conversions @@ -452,7 +453,8 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument( expectedType, this, receiverInfo, - convertedArgument?.unknownIntegerType?.unwrap() + convertedArgument?.unknownIntegerType?.unwrap(), + inferenceSession ) addResolvedKtPrimitive(resolvedAtom) @@ -465,7 +467,8 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument( expectedType, this@resolveKotlinArgument, receiverInfo, - convertedArgument?.unknownIntegerType?.unwrap() + convertedArgument?.unknownIntegerType?.unwrap(), + inferenceSession ) if (!hasContradiction) { @@ -496,7 +499,8 @@ private fun KotlinResolutionCandidate.resolveKotlinArgument( convertedTypeAfterSubtyping, this@resolveKotlinArgument, receiverInfo, - convertedArgument?.unknownIntegerType?.unwrap() + convertedArgument?.unknownIntegerType?.unwrap(), + inferenceSession ) addResolvedKtPrimitive(resolvedAtom) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt index 243749feb43..8d5343eeca9 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/SimpleArgumentsChecks.kt @@ -51,10 +51,11 @@ fun checkSimpleArgument( expectedType: UnwrappedType?, diagnosticsHolder: KotlinDiagnosticsHolder, receiverInfo: ReceiverInfo, - convertedType: UnwrappedType? + convertedType: UnwrappedType?, + inferenceSession: InferenceSession? ): ResolvedAtom = when (argument) { is ExpressionKotlinCallArgument -> checkExpressionArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo.isReceiver, convertedType) - is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo) + is SubKotlinCallArgument -> checkSubCallArgument(csBuilder, argument, expectedType, diagnosticsHolder, receiverInfo, inferenceSession) else -> unexpectedArgument(argument) } @@ -178,8 +179,11 @@ private fun checkSubCallArgument( expectedType: UnwrappedType?, diagnosticsHolder: KotlinDiagnosticsHolder, receiverInfo: ReceiverInfo, + inferenceSession: InferenceSession? ): ResolvedAtom { - val subCallResult = ResolvedSubCallArgument(subCallArgument) + val subCallResult = ResolvedSubCallArgument( + subCallArgument, receiverInfo.isReceiver && inferenceSession?.resolveReceiverIndependently() == true + ) if (expectedType == null) return subCallResult diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt index da81e6be649..e32895c0cb1 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinResolverContext.kt @@ -65,8 +65,10 @@ class SimpleCandidateFactory( init { val baseSystem = NewConstraintSystemImpl(callComponents.constraintInjector, callComponents.builtIns) - baseSystem.addSubsystemFromArgument(kotlinCall.explicitReceiver) - baseSystem.addSubsystemFromArgument(kotlinCall.dispatchReceiverForInvokeExtension) + if (!inferenceSession.resolveReceiverIndependently()) { + baseSystem.addSubsystemFromArgument(kotlinCall.explicitReceiver) + baseSystem.addSubsystemFromArgument(kotlinCall.dispatchReceiverForInvokeExtension) + } for (argument in kotlinCall.argumentsInParenthesis) { baseSystem.addSubsystemFromArgument(argument) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt index 3129ec2dc60..37d642816ef 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/ResolutionAtoms.kt @@ -83,9 +83,12 @@ class ResolvedExpressionAtom(override val atom: ExpressionKotlinCallArgument) : } } -class ResolvedSubCallArgument(override val atom: SubKotlinCallArgument) : ResolvedAtom() { +class ResolvedSubCallArgument(override val atom: SubKotlinCallArgument, resolveIndependently: Boolean) : ResolvedAtom() { init { - setAnalyzedResults(listOf(atom.callResult)) + if (resolveIndependently) + setAnalyzedResults(listOf()) + else + setAnalyzedResults(listOf(atom.callResult)) } } diff --git a/compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt b/compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt new file mode 100644 index 00000000000..71cd307314e --- /dev/null +++ b/compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt @@ -0,0 +1,18 @@ +// IGNORE_BACKEND_FIR: JVM_IR +// WITH_RUNTIME + +import kotlin.reflect.KProperty + +interface DelegateProvider { + operator fun provideDelegate(receiver: Any?, prop: kotlin.reflect.KProperty<*>): Lazy +} +fun delegate(): DelegateProvider = object : DelegateProvider { + override fun provideDelegate(receiver: Any?, prop: KProperty<*>): Lazy { + return lazy { "OK" } as Lazy + } +} + +fun box(): String { + val value: String by delegate() + return value +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/commonCaseForInference.kt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/commonCaseForInference.kt index 642a990d0dd..52a71f4abe5 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/commonCaseForInference.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/commonCaseForInference.kt @@ -9,6 +9,6 @@ object CommonCase { operator fun Fas.provideDelegate(host: D, p: Any?): Fas = TODO() operator fun Fas.getValue(receiver: E, p: Any?): R = TODO() - val Long.test1: String by delegate() // common test, not working because of Inference1 + val Long.test1: String by delegate() // common test, not working because of Inference1 val Long.test2: String by delegate() // should work } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/inferenceFromReceiver2.kt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/inferenceFromReceiver2.kt index e3acda6d2ce..f1b9220922f 100644 --- a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/inferenceFromReceiver2.kt +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/inferenceFromReceiver2.kt @@ -9,6 +9,6 @@ object Inference2 { operator fun Foo.provideDelegate(host: T, p: Any?): Foo = TODO() operator fun Foo.getValue(receiver: Inference2, p: Any?): String = TODO() - val test1: String by delegate() // same story like in Inference1 + val test1: String by delegate() // same story like in Inference1 val test2: String by delegate() } diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt new file mode 100644 index 00000000000..8c100d1a814 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt @@ -0,0 +1,11 @@ +// FIR_IDENTICAL + +val test: String by materializeDelegate() + +fun materializeDelegate(): Delegate = Delegate() + +operator fun K.provideDelegate(receiver: Any?, property: kotlin.reflect.KProperty<*>): K = this + +class Delegate { + operator fun getValue(thisRef: Any?, property: kotlin.reflect.KProperty<*>): V = TODO() +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.txt b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.txt new file mode 100644 index 00000000000..5deca329f99 --- /dev/null +++ b/compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.txt @@ -0,0 +1,13 @@ +package + +public val test: kotlin.String +public fun materializeDelegate(): Delegate +public operator fun K.provideDelegate(/*0*/ receiver: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): K + +public final class Delegate { + public constructor Delegate() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ property: kotlin.reflect.KProperty<*>): V + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + 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 ad3afc99013..01e1d5b0f0c 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -6138,6 +6138,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt"); } + @TestMetadata("provideDelegateResolutionWithStubTypes.kt") + public void testProvideDelegateResolutionWithStubTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); + } + @TestMetadata("setValue.kt") public void testSetValue() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java index 1331ab17da1..1eb77dd1f0a 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsUsingJavacTestGenerated.java @@ -6133,6 +6133,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateOperatorDeclaration.kt"); } + @TestMetadata("provideDelegateResolutionWithStubTypes.kt") + public void testProvideDelegateResolutionWithStubTypes() throws Exception { + runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/provideDelegateResolutionWithStubTypes.kt"); + } + @TestMetadata("setValue.kt") public void testSetValue() throws Exception { runTest("compiler/testData/diagnostics/tests/delegatedProperty/provideDelegate/setValue.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 6a59ed5dfb1..b3f2e100bc7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -10742,6 +10742,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/generic.kt"); } + @TestMetadata("genericDelegateWithNoAdditionalInfo.kt") + public void testGenericDelegateWithNoAdditionalInfo() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt"); + } + @TestMetadata("hostCheck.kt") public void testHostCheck() throws Exception { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/hostCheck.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 257d8894889..f21f7f0c8d7 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -10742,6 +10742,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/generic.kt"); } + @TestMetadata("genericDelegateWithNoAdditionalInfo.kt") + public void testGenericDelegateWithNoAdditionalInfo() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt"); + } + @TestMetadata("hostCheck.kt") public void testHostCheck() throws Exception { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/hostCheck.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 55486423fe0..0a3e68e40c8 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -9527,6 +9527,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/generic.kt"); } + @TestMetadata("genericDelegateWithNoAdditionalInfo.kt") + public void testGenericDelegateWithNoAdditionalInfo() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt"); + } + @TestMetadata("hostCheck.kt") public void testHostCheck() throws Exception { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/hostCheck.kt"); diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/StubType.kt b/core/descriptors/src/org/jetbrains/kotlin/types/StubType.kt index 85e3d81a2bc..675395a4f8d 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/StubType.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/StubType.kt @@ -13,14 +13,34 @@ import org.jetbrains.kotlin.types.refinement.TypeRefinement // This type is used as a stub for postponed type variables, which are important for coroutine inference class StubType( - private val originalTypeVariable: TypeConstructor, - override val isMarkedNullable: Boolean, - override val constructor: TypeConstructor = - ErrorUtils.createErrorTypeConstructor("Constructor for non fixed type: $originalTypeVariable"), - override val memberScope: MemberScope = - ErrorUtils.createErrorScope("Scope for non fixed type: $originalTypeVariable") -) : SimpleType(), StubTypeMarker { + originalTypeVariable: TypeConstructor, + isMarkedNullable: Boolean, + constructor: TypeConstructor = ErrorUtils.createErrorTypeConstructor("Constructor for non fixed type: $originalTypeVariable"), + memberScope: MemberScope = ErrorUtils.createErrorScope("Scope for non fixed type: $originalTypeVariable") +) : AbstractStubType(originalTypeVariable, isMarkedNullable, constructor, memberScope), StubTypeMarker { + override fun materialize(newNullability: Boolean): AbstractStubType { + return StubType(originalTypeVariable, newNullability, constructor, memberScope) + } +} +// This type is used as a replacement of type variables for provideDelegate resolve +class StubTypeForProvideDelegateReceiver( + originalTypeVariable: TypeConstructor, + isMarkedNullable: Boolean, + constructor: TypeConstructor = ErrorUtils.createErrorTypeConstructor("Constructor for non fixed type: $originalTypeVariable"), + memberScope: MemberScope = ErrorUtils.createErrorScope("Scope for non fixed type: $originalTypeVariable") +) : AbstractStubType(originalTypeVariable, isMarkedNullable, constructor, memberScope) { + override fun materialize(newNullability: Boolean): StubTypeForProvideDelegateReceiver { + return StubTypeForProvideDelegateReceiver(originalTypeVariable, newNullability, constructor, memberScope) + } +} + +abstract class AbstractStubType( + protected val originalTypeVariable: TypeConstructor, + override val isMarkedNullable: Boolean, + override val constructor: TypeConstructor, + override val memberScope: MemberScope +) : SimpleType() { override val arguments: List get() = emptyList() @@ -30,10 +50,7 @@ class StubType( override fun replaceAnnotations(newAnnotations: Annotations): SimpleType = this override fun makeNullableAsSpecified(newNullability: Boolean): SimpleType { - return if (newNullability == isMarkedNullable) - this - else - StubType(originalTypeVariable, newNullability, constructor, memberScope) + return if (newNullability == isMarkedNullable) this else materialize(newNullability) } override fun toString(): String { @@ -42,4 +59,6 @@ class StubType( @TypeRefinement override fun refine(kotlinTypeRefiner: KotlinTypeRefiner) = this -} + + abstract fun materialize(newNullability: Boolean): AbstractStubType +} \ No newline at end of file diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index 956947283d6..bb38d9b1013 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -8182,6 +8182,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/generic.kt"); } + @TestMetadata("genericDelegateWithNoAdditionalInfo.kt") + public void testGenericDelegateWithNoAdditionalInfo() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt"); + } + @TestMetadata("hostCheck.kt") public void testHostCheck() throws Exception { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/hostCheck.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index b5339f3e639..51daf31091b 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -8182,6 +8182,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/generic.kt"); } + @TestMetadata("genericDelegateWithNoAdditionalInfo.kt") + public void testGenericDelegateWithNoAdditionalInfo() throws Exception { + runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/genericDelegateWithNoAdditionalInfo.kt"); + } + @TestMetadata("hostCheck.kt") public void testHostCheck() throws Exception { runTest("compiler/testData/codegen/box/delegatedProperty/provideDelegate/hostCheck.kt");