diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index 0f94ffbc52d..0cf8de47ccf 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -13944,6 +13944,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt47744.kt"); } + @Test + @TestMetadata("kt49828.kt") + public void testKt49828() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt"); + } + @Test @TestMetadata("kt49829.kt") public void testKt49829() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index 4862a86ee4a..5bde576f09f 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -13944,6 +13944,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt47744.kt"); } + @Test + @TestMetadata("kt49828.kt") + public void testKt49828() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt"); + } + @Test @TestMetadata("kt49829.kt") public void testKt49829() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index 082e0ae9865..a8ce16d304c 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -13944,6 +13944,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt47744.kt"); } + @Test + @TestMetadata("kt49828.kt") + public void testKt49828() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt"); + } + @Test @TestMetadata("kt49829.kt") public void testKt49829() throws Exception { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 3cc87a1fab6..aee14257b68 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -27,8 +27,10 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData; import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData; +import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.tower.WrongResolutionToClassifier; +import org.jetbrains.kotlin.resolve.calls.util.BuilderLambdaLabelingInfo; import org.jetbrains.kotlin.resolve.deprecation.DescriptorBasedDeprecationInfo; import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible; import org.jetbrains.kotlin.serialization.deserialization.IncompatibleVersionErrorData; @@ -839,6 +841,9 @@ public interface Errors { DiagnosticFactory0 NOT_A_CLASS = DiagnosticFactory0.create(ERROR); DiagnosticFactory1>> OVERLOAD_RESOLUTION_AMBIGUITY = DiagnosticFactory1.create(ERROR); + DiagnosticFactory3 OVERLOAD_RESOLUTION_AMBIGUITY_BECAUSE_OF_STUB_TYPES = DiagnosticFactory3.create(ERROR); + DiagnosticFactory3 STUB_TYPE_IN_ARGUMENT_CAUSES_AMBIGUITY = DiagnosticFactory3.create(ERROR); + DiagnosticFactory4 STUB_TYPE_IN_RECEIVER_CAUSES_AMBIGUITY = DiagnosticFactory4.create(ERROR); DiagnosticFactory1>> NONE_APPLICABLE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1>> CANNOT_COMPLETE_RESOLVE = DiagnosticFactory1.create(ERROR); DiagnosticFactory1>> UNRESOLVED_REFERENCE_WRONG_RECEIVER = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index a7b698f2203..9f72b3b0dcb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -917,6 +917,11 @@ public class DefaultErrorMessages { ELEMENT_TEXT, STRING, ELEMENT_TEXT); MAP.put(OVERLOAD_RESOLUTION_AMBIGUITY, "Overload resolution ambiguity: {0}", AMBIGUOUS_CALLS); + MAP.put(OVERLOAD_RESOLUTION_AMBIGUITY_BECAUSE_OF_STUB_TYPES, "The builder `{0}` you are using has a type argument for type parameter(s) `{1}` that was not explicitly specified. " + + "Without knowing the type of `{1}` compiler cannot choose which overloaded function `{2}` to call here. " + + "Please, either specify the type `{1}` explicitly in `{0}` builder or use explicit cast to a specific type for parameter or receiver (see specific errors on them).", STRING, STRING, STRING); + MAP.put(STUB_TYPE_IN_ARGUMENT_CAUSES_AMBIGUITY, "Type of an argument hasn't inferred yet. To disambiguate this call, please use explicit cast for the parameter to {1} if you rely a type argument for type parameter(s) {2} to be inferred to {3}", RENDER_TYPE, STRING, STRING); + MAP.put(STUB_TYPE_IN_RECEIVER_CAUSES_AMBIGUITY, "Type of a receiver hasn't inferred yet. To disambiguate this call, please use explicit cast for the receiver to {1} if you rely a type argument for type parameter(s) {2} to be inferred to {3}", RENDER_TYPE, STRING, STRING, null); MAP.put(NONE_APPLICABLE, "None of the following functions can be called with the arguments supplied: {0}", AMBIGUOUS_CALLS); MAP.put(CANNOT_COMPLETE_RESOLVE, "Cannot choose among the following candidates without completing type inference: {0}", AMBIGUOUS_CALLS); MAP.put(UNRESOLVED_REFERENCE_WRONG_RECEIVER, "Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: {0}", AMBIGUOUS_CALLS); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallCheckerWithAdditionalResolve.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallCheckerWithAdditionalResolve.kt new file mode 100644 index 00000000000..63d3c6fe170 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/CallCheckerWithAdditionalResolve.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.checkers + +import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults +import org.jetbrains.kotlin.resolve.calls.tower.ImplicitScopeTower +import org.jetbrains.kotlin.types.UnwrappedType + +interface CallCheckerWithAdditionalResolve { + fun check( + overloadResolutionResults: OverloadResolutionResults<*>, + scopeTower: ImplicitScopeTower, + resolutionCallbacks: KotlinResolutionCallbacks, + expectedType: UnwrappedType?, + context: BasicCallResolutionContext, + ) +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt index c9196ff7ae5..f10a37c0364 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/BuilderInferenceSession.kt @@ -217,11 +217,13 @@ class BuilderInferenceSession( override fun currentConstraintSystem() = ConstraintStorage.Empty - fun getNotFixedToInferredTypesSubstitutor(): NewTypeSubstitutor { - val currentSubstitutor = - commonSystem.buildCurrentSubstitutor().cast().takeIf { !it.isEmpty } ?: return EmptySubstitutor - return ComposedSubstitutor(currentSubstitutor, createNonFixedTypeToVariableSubstitutor()) - } + fun getNotFixedToInferredTypesSubstitutor(): NewTypeSubstitutor = + ComposedSubstitutor(getCurrentSubstitutor(), createNonFixedTypeToVariableSubstitutor()) + + fun getUsedStubTypes(): Set = stubsForPostponedVariables.values.toSet() + + fun getCurrentSubstitutor(): NewTypeSubstitutor = + commonSystem.buildCurrentSubstitutor().cast().takeIf { !it.isEmpty } ?: EmptySubstitutor override fun initializeLambda(lambda: ResolvedLambdaAtom) { this.lambda = lambda diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt index 48c3c4d6d5b..64b90c103ca 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/KotlinResolutionCallbacksImpl.kt @@ -208,13 +208,11 @@ class KotlinResolutionCallbacksImpl( kotlinToResolvedCallTransformer, expressionTypingServices, argumentTypeResolver, doubleColonExpressionResolver, deprecationResolver, moduleDescriptor, typeApproximator, missingSupertypesResolver, lambdaArgument - ) + ).apply { lambdaArgument.builderInferenceSession = this } } else { null } - lambdaArgument.builderInferenceSession = builderInferenceSession - val temporaryTrace = if (builderInferenceSession != null) TemporaryBindingTrace.create(trace, "Trace to resolve builder inference lambda: $lambdaArgument") else diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt index e559ec97ba7..dfaedb79673 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/PSICallResolver.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.resolve.calls.tasks.OldResolutionCandidate import org.jetbrains.kotlin.resolve.calls.tasks.TracingStrategy import org.jetbrains.kotlin.resolve.calls.util.* import org.jetbrains.kotlin.resolve.checkers.PassingProgressionAsCollectionCallChecker +import org.jetbrains.kotlin.resolve.checkers.ResolutionWithStubTypesChecker import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator import org.jetbrains.kotlin.resolve.deprecation.DeprecationResolver import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns @@ -78,7 +79,10 @@ class PSICallResolver( private val missingSupertypesResolver: MissingSupertypesResolver, private val resultTypeResolver: ResultTypeResolver, ) { - private val callCheckersWithAdditionalResolve = listOf(PassingProgressionAsCollectionCallChecker(kotlinCallResolver)) + private val callCheckersWithAdditionalResolve = listOf( + PassingProgressionAsCollectionCallChecker(kotlinCallResolver), + ResolutionWithStubTypesChecker(kotlinCallResolver) + ) private val givenCandidatesName = Name.special("") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/StubTypesBasedInferenceSession.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/StubTypesBasedInferenceSession.kt index 8eb9b72928c..1f62d96428a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/StubTypesBasedInferenceSession.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/tower/StubTypesBasedInferenceSession.kt @@ -29,7 +29,7 @@ abstract class StubTypesBasedInferenceSession( val builtIns: KotlinBuiltIns ) : InferenceSession { protected val partiallyResolvedCallsInfo = arrayListOf() - private val errorCallsInfo = arrayListOf>() + val errorCallsInfo = arrayListOf>() private val completedCalls = hashSetOf() protected val nestedInferenceSessions = hashSetOf>() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallResolverUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallResolverUtil.kt index c282307897d..bb76950107e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallResolverUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/CallResolverUtil.kt @@ -19,26 +19,34 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.calls.CallTransformer +import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.components.isVararg +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +import org.jetbrains.kotlin.resolve.calls.inference.ComposedSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem +import org.jetbrains.kotlin.resolve.calls.inference.components.EmptySubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeVariables -import org.jetbrains.kotlin.resolve.calls.model.ResolvedValueArgument +import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind import org.jetbrains.kotlin.resolve.calls.tasks.OldResolutionCandidate +import org.jetbrains.kotlin.resolve.calls.tower.* import org.jetbrains.kotlin.resolve.descriptorUtil.isParameterOfAnnotation import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes import org.jetbrains.kotlin.resolve.scopes.collectSyntheticConstructors import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.resolve.scopes.utils.getImplicitReceiversHierarchy import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.typeUtil.contains +import org.jetbrains.kotlin.util.buildNotFixedVariablesToPossibleResultType import org.jetbrains.kotlin.utils.SmartList enum class ResolveArgumentsMode { @@ -328,3 +336,43 @@ internal fun PsiElement.reportOnElement() = ?.takeIf { isImplicit } ?.let { getStrictParentOfType()!! } ?: this + +internal fun List.replaceTypes( + context: BasicCallResolutionContext, + resolutionCallbacks: KotlinResolutionCallbacks, + replace: (Int, UnwrappedType) -> UnwrappedType?, +): List = mapIndexed { i, argument -> + if (argument !is SimpleKotlinCallArgument) return@mapIndexed argument + + val psiExpression = argument.psiExpression ?: return@mapIndexed argument + val argumentSubstitutor = if (argument is SubKotlinCallArgument) { + val notFixedVariablesSubstitutor = + argument.callResult.constraintSystem.buildNotFixedVariablesToPossibleResultType(resolutionCallbacks) as NewTypeSubstitutor + val fixedVariablesSubstitutor = + argument.callResult.constraintSystem.getBuilder().buildCurrentSubstitutor() as NewTypeSubstitutor + + ComposedSubstitutor(notFixedVariablesSubstitutor, fixedVariablesSubstitutor) + } else EmptySubstitutor + + val newType = replace(i, argumentSubstitutor.safeSubstitute(argument.receiver.receiverValue.type.unwrap())) + ?: return@mapIndexed argument + + ExpressionKotlinCallArgumentImpl( + argument.psiCallArgument.valueArgument, + argument.psiCallArgument.dataFlowInfoBeforeThisArgument, + argument.psiCallArgument.dataFlowInfoAfterThisArgument, + ReceiverValueWithSmartCastInfo( + ExpressionReceiver.create(psiExpression, newType, context.trace.bindingContext), + typesFromSmartCasts = emptySet(), + isStable = true + ) + ) +} + +internal fun PSIKotlinCall.replaceArguments( + newArguments: List, + newReceiverArgument: ReceiverExpressionKotlinCallArgument? = null, +): PSIKotlinCall = PSIKotlinCallImpl( + callKind, psiCall, tracingStrategy, newReceiverArgument, dispatchReceiverForInvokeExtension, name, typeArguments, newArguments, + externalArgument, startingDataFlowInfo, resultDataFlowInfo, dataFlowInfoForArguments, isForImplicitInvoke +) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/builderInferenceUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/builderInferenceUtil.kt new file mode 100644 index 00000000000..37dc2cabb95 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/util/builderInferenceUtil.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.calls.util + +import org.jetbrains.kotlin.psi.KtLambdaExpression + +class BuilderLambdaLabelingInfo(val builderLambda: KtLambdaExpression?) { + companion object { + val EMPTY = BuilderLambdaLabelingInfo(null) + } + + override fun toString(): String { + return builderLambda.toString() + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PassingProgressionAsCollectionCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PassingProgressionAsCollectionCallChecker.kt index 839cd737b1d..ec3c86c95e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PassingProgressionAsCollectionCallChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/PassingProgressionAsCollectionCallChecker.kt @@ -7,21 +7,18 @@ package org.jetbrains.kotlin.resolve.checkers import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.diagnostics.Errors.PROGRESSIONS_CHANGING_RESOLVE -import org.jetbrains.kotlin.resolve.BindingTrace import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerWithAdditionalResolve import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext -import org.jetbrains.kotlin.resolve.calls.model.KotlinCallArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.SimpleKotlinCallArgument import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.tower.* +import org.jetbrains.kotlin.resolve.calls.util.replaceArguments +import org.jetbrains.kotlin.resolve.calls.util.replaceTypes import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValueWithSmartCastInfo import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerState import org.jetbrains.kotlin.types.checker.ClassicTypeCheckerStateInternals @@ -33,7 +30,7 @@ import org.jetbrains.kotlin.types.typeUtil.isTypeParameter Please don't use similar logic for other checkers */ @OptIn(ClassicTypeCheckerStateInternals::class) -class PassingProgressionAsCollectionCallChecker(private val kotlinCallResolver: KotlinCallResolver) { +class PassingProgressionAsCollectionCallChecker(private val kotlinCallResolver: KotlinCallResolver) : CallCheckerWithAdditionalResolve { private val typeCheckerState = ClassicTypeCheckerState(isErrorTypeEqualsToAnything = false) private val iterableProgressions = listOf( @@ -67,14 +64,21 @@ class PassingProgressionAsCollectionCallChecker(private val kotlinCallResolver: if (progressionOrRangeArgumentTypes.all { it == null }) return val builtIns = resolvedCall.candidateDescriptor.builtIns - val newArguments = replaceArgumentsWithCollectionIfNeeded(valueArguments, progressionOrRangeArgumentTypes, context.trace, builtIns) - val newCall = PSIKotlinCallImpl( - kotlinCall.callKind, kotlinCall.psiCall, kotlinCall.tracingStrategy, kotlinCall.explicitReceiver, - kotlinCall.dispatchReceiverForInvokeExtension, kotlinCall.name, kotlinCall.typeArguments, newArguments, - kotlinCall.externalArgument, kotlinCall.startingDataFlowInfo, kotlinCall.resultDataFlowInfo, - kotlinCall.dataFlowInfoForArguments, kotlinCall.isForImplicitInvoke - ) + val newArguments = valueArguments.replaceTypes(context, resolutionCallbacks) { i, type -> + val progressionOrRangeElementType = progressionOrRangeArgumentTypes[i] ?: return@replaceTypes null + intersectTypes( + listOf( + KotlinTypeFactory.simpleNotNullType( + TypeAttributes.Empty, + builtIns.collection, + listOf(TypeProjectionImpl(progressionOrRangeElementType)) + ), + type + ) + ) + } + val newCall = kotlinCall.replaceArguments(newArguments) val candidateForCollectionReplacedArgument = kotlinCallResolver.resolveCall( scopeTower, resolutionCallbacks, newCall, expectedType, context.collectAllCandidates @@ -129,7 +133,7 @@ class PassingProgressionAsCollectionCallChecker(private val kotlinCallResolver: } } - fun check( + override fun check( overloadResolutionResults: OverloadResolutionResults<*>, scopeTower: ImplicitScopeTower, resolutionCallbacks: KotlinResolutionCallbacks, @@ -149,36 +153,4 @@ class PassingProgressionAsCollectionCallChecker(private val kotlinCallResolver: builtIns.collection, listOf(TypeProjectionImpl(builtIns.nullableAnyType)) ) - - private fun replaceArgumentsWithCollectionIfNeeded( - valueArguments: List, - progressionOrRangeArgumentTypes: List, - trace: BindingTrace, - builtIns: KotlinBuiltIns - ): List = valueArguments.mapIndexed { i, argument -> - if (argument !is ExpressionKotlinCallArgumentImpl) return@mapIndexed argument - val progressionOrRangeElementType = progressionOrRangeArgumentTypes[i] ?: return@mapIndexed argument - val psiExpression = argument.psiExpression ?: return@mapIndexed argument - val newType = intersectTypes( - listOf( - KotlinTypeFactory.simpleNotNullType( - TypeAttributes.Empty, - builtIns.collection, - listOf(TypeProjectionImpl(progressionOrRangeElementType)) - ), - argument.receiver.receiverValue.type.unwrap() - ) - ) - - ExpressionKotlinCallArgumentImpl( - argument.psiCallArgument.valueArgument, - DataFlowInfo.EMPTY, - DataFlowInfo.EMPTY, - ReceiverValueWithSmartCastInfo( - ExpressionReceiver.create(psiExpression, newType, trace.bindingContext), - emptySet(), - true - ) - ) - } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ResolutionWithStubTypesChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ResolutionWithStubTypesChecker.kt new file mode 100644 index 00000000000..16c478565b8 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/checkers/ResolutionWithStubTypesChecker.kt @@ -0,0 +1,200 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.resolve.checkers + +import org.jetbrains.kotlin.diagnostics.Errors.* +import org.jetbrains.kotlin.psi.KtLambdaExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.calls.KotlinCallResolver +import org.jetbrains.kotlin.resolve.calls.checkers.CallCheckerWithAdditionalResolve +import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks +import org.jetbrains.kotlin.resolve.calls.components.stableType +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.inference.BuilderInferenceSession +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor +import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutorByConstructorMap +import org.jetbrains.kotlin.resolve.calls.model.* +import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults +import org.jetbrains.kotlin.resolve.calls.tower.* +import org.jetbrains.kotlin.resolve.calls.util.BuilderLambdaLabelingInfo +import org.jetbrains.kotlin.resolve.calls.util.replaceArguments +import org.jetbrains.kotlin.resolve.calls.util.replaceTypes +import org.jetbrains.kotlin.resolve.scopes.receivers.* +import org.jetbrains.kotlin.types.* +import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor + +class ResolutionWithStubTypesChecker(private val kotlinCallResolver: KotlinCallResolver) : CallCheckerWithAdditionalResolve { + override fun check( + overloadResolutionResults: OverloadResolutionResults<*>, + scopeTower: ImplicitScopeTower, + resolutionCallbacks: KotlinResolutionCallbacks, + expectedType: UnwrappedType?, + context: BasicCallResolutionContext, + ) { + // Don't check builder inference lambdas if the entire builder call itself has resolution ambiguity + if (!overloadResolutionResults.isSingleResult) return + + val builderResolvedCall = overloadResolutionResults.resultingCall as? NewAbstractResolvedCall<*> ?: return + + val builderLambdas = (builderResolvedCall.psiKotlinCall.argumentsInParenthesis + builderResolvedCall.psiKotlinCall.externalArgument) + .filterIsInstance() + .filter { it.hasBuilderInferenceAnnotation } + + for (lambda in builderLambdas) { + val builderInferenceSession = lambda.builderInferenceSession as? BuilderInferenceSession ?: continue + val errorCalls = builderInferenceSession.errorCallsInfo + for (errorCall in errorCalls) { + val resolutionResult = errorCall.result + if (resolutionResult.isAmbiguity) { + val firstResolvedCall = resolutionResult.resultingCalls.first() as? NewAbstractResolvedCall<*> ?: continue + processResolutionAmbiguityError(context, firstResolvedCall, lambda, resolutionCallbacks, expectedType, scopeTower) + } + } + } + } + + private fun processResolutionAmbiguityError( + context: BasicCallResolutionContext, + firstResolvedCall: NewAbstractResolvedCall<*>, + lambda: LambdaKotlinCallArgument, + resolutionCallbacks: KotlinResolutionCallbacks, + expectedType: UnwrappedType?, + scopeTower: ImplicitScopeTower, + ) { + val kotlinCall = firstResolvedCall.psiKotlinCall + val calleeExpression = kotlinCall.psiCall.calleeExpression + val builderCalleeExpression = context.call.calleeExpression + + if (calleeExpression == null || builderCalleeExpression == null) return + + val receiverValue = firstResolvedCall.extensionReceiver + val valueArguments = kotlinCall.argumentsInParenthesis + + val builderInferenceSession = lambda.builderInferenceSession as BuilderInferenceSession + val stubVariablesSubstitutor = builderInferenceSession.getNotFixedToInferredTypesSubstitutor() + val variablesForUsedStubTypes = builderInferenceSession.getUsedStubTypes().map { it.originalTypeVariable } + val typeVariablesSubstitutionMap = (builderInferenceSession.getCurrentSubstitutor() as NewTypeSubstitutorByConstructorMap).map + .filterKeys { it in variablesForUsedStubTypes } + + val newReceiverArgument = receiverValue?.buildSubstitutedReceiverArgument(stubVariablesSubstitutor, context) + val newArguments = valueArguments.replaceTypes(context, resolutionCallbacks) { _, type -> + stubVariablesSubstitutor.safeSubstitute(type) + } + + if (newReceiverArgument == null && valueArguments == newArguments) return + + val newCall = kotlinCall.replaceArguments(newArguments, newReceiverArgument) + val candidatesForSubstitutedCall = kotlinCallResolver.resolveCall( + scopeTower, resolutionCallbacks, newCall, expectedType, context.collectAllCandidates + ) + + // It means we can't disambiguate the call with substituted receiver and arguments + if (candidatesForSubstitutedCall.size != 1) return + + val typeVariablesCausedAmbiguity = reportStubTypeCausesAmbiguityOnArgumentsIfNeeded( + valueArguments, newArguments, context, typeVariablesSubstitutionMap + ).toMutableSet() + + val newReceiverValue = newReceiverArgument?.receiverValue + + if (receiverValue != null && newReceiverValue != null) { + typeVariablesCausedAmbiguity.addAll( + reportStubTypeCausesAmbiguityOnReceiverIfNeeded( + receiverValue, newReceiverValue, kotlinCall, lambda, context, typeVariablesSubstitutionMap + ) + ) + } + + if (typeVariablesCausedAmbiguity.isNotEmpty()) { + context.trace.report( + OVERLOAD_RESOLUTION_AMBIGUITY_BECAUSE_OF_STUB_TYPES.on( + calleeExpression, + builderCalleeExpression.toString(), + typeVariablesCausedAmbiguity.toString(), + calleeExpression.toString() + ) + ) + } + } + + private fun reportStubTypeCausesAmbiguityOnReceiverIfNeeded( + receiver: ReceiverValue, + newReceiver: ReceiverValue, + kotlinCall: PSIKotlinCall, + lambda: LambdaKotlinCallArgument, + context: BasicCallResolutionContext, + substitutionMap: Map + ): Set = buildSet { + val receiverType = receiver.type + val newReceiverType = newReceiver.type + val relatedLambdaToLabel = (lambda.psiExpression as? KtLambdaExpression)?.takeIf { + val lexicalScope = context.trace.bindingContext[BindingContext.LEXICAL_SCOPE, kotlinCall.psiCall.callElement] + val nearestScopeDescriptor = lexicalScope?.ownerDescriptor + // Don't need to store lambda psi element if it can be accessed though unmarked `this` + nearestScopeDescriptor != null && nearestScopeDescriptor != (receiver as? ExtensionReceiver)?.declarationDescriptor + } + + if (receiverType != newReceiverType) { + val typeVariables = substitutionMap.map { it.key as NewTypeVariableConstructor } + val typeParameters = typeVariables.joinToString { (it.originalTypeParameter?.name ?: it).toString() } + val inferredTypes = substitutionMap.values.joinToString() + + addAll(typeVariables) + + context.trace.report( + STUB_TYPE_IN_RECEIVER_CAUSES_AMBIGUITY.on( + kotlinCall.explicitReceiver?.psiExpression ?: kotlinCall.psiCall.callElement, + newReceiverType, typeParameters, inferredTypes, + if (relatedLambdaToLabel != null) BuilderLambdaLabelingInfo(relatedLambdaToLabel) else BuilderLambdaLabelingInfo.EMPTY + ) + ) + } + } + + private fun reportStubTypeCausesAmbiguityOnArgumentsIfNeeded( + valueArguments: List, + newArguments: List, + context: BasicCallResolutionContext, + substitutionMap: Map + ): Set = buildSet { + for ((i, valueArgument) in valueArguments.withIndex()) { + if (valueArgument !is SimpleKotlinCallArgument) continue + + val substitutedValueArgument = newArguments[i] as? SimpleKotlinCallArgument ?: continue + val originalType = valueArgument.receiver.stableType + val substitutedType = substitutedValueArgument.receiver.stableType + + if (originalType != substitutedType) { + val psiExpression = valueArgument.psiExpression ?: continue + val typeVariables = substitutionMap.map { it.key as NewTypeVariableConstructor } + val typeParameters = typeVariables.joinToString { (it.originalTypeParameter?.name ?: it).toString() } + val inferredTypes = substitutionMap.values.joinToString() + + addAll(typeVariables) + + context.trace.report( + STUB_TYPE_IN_ARGUMENT_CAUSES_AMBIGUITY.on(psiExpression, substitutedType, typeParameters, inferredTypes) + ) + } + } + } + + private fun ReceiverValue.buildSubstitutedReceiverArgument( + substitutor: NewTypeSubstitutor, + context: BasicCallResolutionContext, + ): ReceiverExpressionKotlinCallArgument? { + val newType = substitutor.safeSubstitute(type.unwrap()) + val receiverValue = when (this) { + is ExpressionReceiver -> ExpressionReceiver.create(expression, newType, context.trace.bindingContext) + is ExtensionReceiver -> ExtensionReceiver(declarationDescriptor, newType, original) + else -> return null + } + + return ReceiverExpressionKotlinCallArgument( + ReceiverValueWithSmartCastInfo(receiverValue, typesFromSmartCasts = emptySet(), true) + ) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java index df7cb15725d..de0e8a1aa19 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/BasicExpressionTypingVisitor.java @@ -373,7 +373,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor { return; } - if (!CastDiagnosticsUtil.isCastPossible(actualType, targetType, components.platformToKotlinClassMapper) && !TypeUtilsKt.isStubType(actualType)) { + if (!TypeUtilsKt.isStubType(actualType) && !CastDiagnosticsUtil.isCastPossible(actualType, targetType, components.platformToKotlinClassMapper)) { context.trace.report(CAST_NEVER_SUCCEEDS.on(expression.getOperationReference())); return; } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ClassicTypeSystemContextForCS.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ClassicTypeSystemContextForCS.kt index c9978a8a7ad..8e5e15c1787 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ClassicTypeSystemContextForCS.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/components/ClassicTypeSystemContextForCS.kt @@ -78,14 +78,14 @@ class ClassicTypeSystemContextForCS( override fun createStubTypeForBuilderInference(typeVariable: TypeVariableMarker): StubTypeMarker { return StubTypeForBuilderInference( - typeVariable.freshTypeConstructor() as TypeConstructor, + typeVariable.freshTypeConstructor() as NewTypeVariableConstructor, typeVariable.defaultType().isMarkedNullable() ) } override fun createStubTypeForTypeVariablesInSubtyping(typeVariable: TypeVariableMarker): StubTypeMarker { return StubTypeForTypeVariablesInSubtyping( - typeVariable.freshTypeConstructor() as TypeConstructor, + typeVariable.freshTypeConstructor() as NewTypeVariableConstructor, typeVariable.defaultType().isMarkedNullable() ) } diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt index e81a98dc10b..ee878131512 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/inference/model/TypeVariable.kt @@ -34,8 +34,7 @@ class TypeVariableTypeConstructor( private val builtIns: KotlinBuiltIns, val debugName: String, override val originalTypeParameter: TypeParameterDescriptor? -) : TypeConstructor, - NewTypeVariableConstructor, TypeVariableTypeConstructorMarker { +) : NewTypeVariableConstructor, TypeVariableTypeConstructorMarker { override fun getParameters(): List = emptyList() override fun getSupertypes(): Collection = emptyList() override fun isFinal(): Boolean = false diff --git a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt index 538650dcc66..27de0c9480e 100644 --- a/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt +++ b/compiler/resolution/src/org/jetbrains/kotlin/resolve/calls/model/KotlinCallArguments.kt @@ -59,11 +59,11 @@ interface LambdaKotlinCallArgument : PostponableKotlinCallArgument { */ var hasBuilderInferenceAnnotation: Boolean get() = false - set(@Suppress("UNUSED_PARAMETER") value) {} + set(_) {} var builderInferenceSession: InferenceSession? get() = null - set(@Suppress("UNUSED_PARAMETER") value) {} + set(_) {} /** * parametersTypes == null means, that there is no declared arguments diff --git a/compiler/resolution/src/org/jetbrains/kotlin/util/InferenceUtils.kt b/compiler/resolution/src/org/jetbrains/kotlin/util/InferenceUtils.kt new file mode 100644 index 00000000000..bf79cd27aea --- /dev/null +++ b/compiler/resolution/src/org/jetbrains/kotlin/util/InferenceUtils.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.util + +import org.jetbrains.kotlin.resolve.calls.components.KotlinResolutionCallbacks +import org.jetbrains.kotlin.resolve.calls.inference.NewConstraintSystem +import org.jetbrains.kotlin.resolve.calls.inference.model.TypeVariableTypeConstructor +import org.jetbrains.kotlin.resolve.calls.inference.model.typeForTypeVariable +import org.jetbrains.kotlin.types.model.TypeSubstitutorMarker + +fun NewConstraintSystem.buildNotFixedVariablesToPossibleResultType(resolutionCallbacks: KotlinResolutionCallbacks): TypeSubstitutorMarker = + asConstraintSystemCompleterContext().typeSubstitutorByTypeConstructor( + getBuilder().currentStorage().notFixedTypeVariables.mapValues { + val typeVariable = it.key as TypeVariableTypeConstructor + resolutionCallbacks.findResultType(this, typeVariable) ?: typeVariable.typeForTypeVariable() + } +) diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.fir.kt b/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.fir.kt new file mode 100644 index 00000000000..9d26d72be01 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.fir.kt @@ -0,0 +1,221 @@ +// WITH_STDLIB +// !DIAGNOSTICS: -OPT_IN_USAGE_ERROR +// For FIR, see: KT-50704 + +@JvmName("foo1") +fun foo(x: Inv) {} +fun foo(x: Inv) {} + +@JvmName("foo21") +fun Inv.foo2() {} +fun Inv.foo2() {} + +@JvmName("bar1") +fun String.bar() {} +fun Int.bar() {} + +class Inv(x: K) + +fun foo0(x: String, y: Float, z: String = "") {} +fun foo0(x: String, y: Float, z: Int = 1) {} + +fun foo00(x: String, y: Number) {} +fun foo00(x: CharSequence, y: Float) {} + +fun foo000(x: String, y: Number, z: String) {} +fun foo000(x: CharSequence, y: Float, z: Int) {} + +fun foo0000(x: String, y: Number, z: String) {} +fun foo0000(x: Int, y: Float, z: Int) {} + +fun foo0001(x: List, y: Number, z: String) {} +fun foo0001(x: String, y: Float, z: Int) {} + +fun foo0002(x: Int, y: Number, z: String) {} +fun foo0002(x: String, y: Float, z: Int) {} + +fun Int.foo0003(y: Number, z: String) {} +fun String.foo0003(y: Float, z: Int) {} + +@JvmName("foo111") +fun foo11(x: MutableSet>) {} +@JvmName("foo112") +fun foo11(x: MutableSet>) {} +fun foo11(x: MutableSet>) {} + +fun main() { + val list1 = buildList { + add("one") + + val secondParameter = get(1) + println(secondParameter) // ERROR: [OVERLOAD_RESOLUTION_AMBIGUITY] Overload resolution ambiguity. All these functions match. + } + val list2 = buildList { + add("one") + + println(get(1)) // ERROR: [OVERLOAD_RESOLUTION_AMBIGUITY] Overload resolution ambiguity. All these functions match. + } + val list3 = buildList { + add("one") + + val secondParameter = Inv(get(1)) + foo(secondParameter) + } + val list4 = buildList { + add("one") + + val secondParameter = get(1) + foo(Inv(secondParameter)) + } + val list5 = buildList { + add("one") + + foo(Inv(get(1))) + } + val list6 = buildList { + add("one") + + get(0).bar() + } + val list7 = buildList { + add("one") + + with (get(0)) { + bar() + } + } + val list71 = buildList { + add("one") + + with (get(0)) l1@ { + with (listOf(1)) { + bar() + } + } + } + val list711 = buildList { + add("one") + + with (get(0)) { + with (listOf(1)) { + bar() + } + } + } + val list8 = buildList { + add("one") + + Inv(get(0)).foo2() + } + val list9 = buildList { + add("one") + + with (get(0)) { + with (Inv(this)) { + foo2() + } + } + } + val list91 = buildList { + add("one") + + with (get(0)) { + with (Inv(this)) { + bar() + } + } + } + + // Resolution ambiguities below aren't due to stub types + val list10 = buildList { + add("one") + + foo0(get(0), 0f) + } + val list11 = buildList { + add("one") + + val x = get(0) + foo0(x, 0f) + } + val list12 = buildList { + add("one") + foo00(get(0), 0f) + } + + // Below are multi-arguments resolution ambiguities + val list13 = buildList { + add("one") + + foo000(get(0), 0f, get(0)) + } + + val list14 = buildList { + add("one") + + foo0000(get(0), 0f, get(0)) + } + + val list17 = buildList l1@ { + add("one") + + with (get(0)) { + foo0003(0f, this@l1.get(0)) + } + } + + val list18 = buildList { + add("one") + + get(0).foo0003(0f, get(0)) + } + + val map1 = buildMap { + put(1, "one") + + foo11(entries) + } + + // There aren't specific errors below as casting value arguments doesn't make a resolve successful + val list15 = buildList { + add("one") + + foo0001(get(0), 0f, get(0)) + } + + val list16 = buildList { + add("one") + + foo0002(get(0), 0f, get(0)) + } +} + +interface Foo { + fun add(x: K) + fun get(): K +} + +interface Foo2 { + fun put(x: K, y: V) + fun get(): MutableSet> + fun entries(): MutableSet> +} + +fun twoBuilderLambdas(@BuilderInference block: Foo.() -> Unit, @BuilderInference block2: Foo2.() -> Unit) {} + +fun test() { + twoBuilderLambdas( + { + add("") + with (get()) { + with (listOf(1)) { + bar() + } + } + }, + { + put(1, "one") + foo11(entries()) + } + ) +} diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt b/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt new file mode 100644 index 00000000000..4ed8dd2e8ac --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt @@ -0,0 +1,221 @@ +// WITH_STDLIB +// !DIAGNOSTICS: -OPT_IN_USAGE_ERROR +// For FIR, see: KT-50704 + +@JvmName("foo1") +fun foo(x: Inv) {} +fun foo(x: Inv) {} + +@JvmName("foo21") +fun Inv.foo2() {} +fun Inv.foo2() {} + +@JvmName("bar1") +fun String.bar() {} +fun Int.bar() {} + +class Inv(x: K) + +fun foo0(x: String, y: Float, z: String = "") {} +fun foo0(x: String, y: Float, z: Int = 1) {} + +fun foo00(x: String, y: Number) {} +fun foo00(x: CharSequence, y: Float) {} + +fun foo000(x: String, y: Number, z: String) {} +fun foo000(x: CharSequence, y: Float, z: Int) {} + +fun foo0000(x: String, y: Number, z: String) {} +fun foo0000(x: Int, y: Float, z: Int) {} + +fun foo0001(x: List, y: Number, z: String) {} +fun foo0001(x: String, y: Float, z: Int) {} + +fun foo0002(x: Int, y: Number, z: String) {} +fun foo0002(x: String, y: Float, z: Int) {} + +fun Int.foo0003(y: Number, z: String) {} +fun String.foo0003(y: Float, z: Int) {} + +@JvmName("foo111") +fun foo11(x: MutableSet>) {} +@JvmName("foo112") +fun foo11(x: MutableSet>) {} +fun foo11(x: MutableSet>) {} + +fun main() { + val list1 = buildList { + add("one") + + val secondParameter = get(1) + println(secondParameter) // ERROR: [OVERLOAD_RESOLUTION_AMBIGUITY] Overload resolution ambiguity. All these functions match. + } + val list2 = buildList { + add("one") + + println(get(1)) // ERROR: [OVERLOAD_RESOLUTION_AMBIGUITY] Overload resolution ambiguity. All these functions match. + } + val list3 = buildList { + add("one") + + val secondParameter = Inv(get(1)) + foo(; E; String")!>secondParameter) + } + val list4 = buildList { + add("one") + + val secondParameter = get(1) + foo(; E; String")!>Inv(secondParameter)) + } + val list5 = buildList { + add("one") + + foo(; E; String")!>Inv(get(1))) + } + val list6 = buildList { + add("one") + + get(0).bar() + } + val list7 = buildList { + add("one") + + with (get(0)) { + bar() + } + } + val list71 = buildList { + add("one") + + with (get(0)) l1@ { + with (listOf(1)) { + bar() + } + } + } + val list711 = buildList { + add("one") + + with (get(0)) { + with (listOf(1)) { + bar() + } + } + } + val list8 = buildList { + add("one") + + ; E; String; null")!>Inv(get(0)).foo2() + } + val list9 = buildList { + add("one") + + with (get(0)) { + with (Inv(this)) { + ; E; String; null")!>foo2() + } + } + } + val list91 = buildList { + add("one") + + with (get(0)) { + with (Inv(this)) { + bar() + } + } + } + + // Resolution ambiguities below aren't due to stub types + val list10 = buildList { + add("one") + + foo0(get(0), 0f) + } + val list11 = buildList { + add("one") + + val x = get(0) + foo0(x, 0f) + } + val list12 = buildList { + add("one") + foo00(get(0), 0f) + } + + // Below are multi-arguments resolution ambiguities + val list13 = buildList { + add("one") + + foo000(get(0), 0f, get(0)) + } + + val list14 = buildList { + add("one") + + foo0000(get(0), 0f, get(0)) + } + + val list17 = buildList l1@ { + add("one") + + with (get(0)) { + foo0003(0f, this@l1.get(0)) + } + } + + val list18 = buildList { + add("one") + + get(0).foo0003(0f, get(0)) + } + + val map1 = buildMap { + put(1, "one") + + foo11(>; K, V; Int, String")!>entries) + } + + // There aren't specific errors below as casting value arguments doesn't make a resolve successful + val list15 = buildList { + add("one") + + foo0001(get(0), 0f, get(0)) + } + + val list16 = buildList { + add("one") + + foo0002(get(0), 0f, get(0)) + } +} + +interface Foo { + fun add(x: K) + fun get(): K +} + +interface Foo2 { + fun put(x: K, y: V) + fun get(): MutableSet> + fun entries(): MutableSet> +} + +fun twoBuilderLambdas(@BuilderInference block: Foo.() -> Unit, @BuilderInference block2: Foo2.() -> Unit) {} + +fun test() { + twoBuilderLambdas( + { + add("") + with (get()) { + with (listOf(1)) { + bar() + } + } + }, + { + put(1, "one") + foo11(>; K, V; Int, String")!>entries()) + } + ) +} diff --git a/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.txt b/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.txt new file mode 100644 index 00000000000..6fe2cd86100 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inference/builderInference/kt49828.txt @@ -0,0 +1,53 @@ +package + +public fun foo(/*0*/ x: Inv): kotlin.Unit +@kotlin.jvm.JvmName(name = "foo1") public fun foo(/*0*/ x: Inv): kotlin.Unit +public fun foo0(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Float, /*2*/ z: kotlin.Int = ...): kotlin.Unit +public fun foo0(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Float, /*2*/ z: kotlin.String = ...): kotlin.Unit +public fun foo00(/*0*/ x: kotlin.CharSequence, /*1*/ y: kotlin.Float): kotlin.Unit +public fun foo00(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Number): kotlin.Unit +public fun foo000(/*0*/ x: kotlin.CharSequence, /*1*/ y: kotlin.Float, /*2*/ z: kotlin.Int): kotlin.Unit +public fun foo000(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Number, /*2*/ z: kotlin.String): kotlin.Unit +public fun foo0000(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Float, /*2*/ z: kotlin.Int): kotlin.Unit +public fun foo0000(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Number, /*2*/ z: kotlin.String): kotlin.Unit +public fun foo0001(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Float, /*2*/ z: kotlin.Int): kotlin.Unit +public fun foo0001(/*0*/ x: kotlin.collections.List, /*1*/ y: kotlin.Number, /*2*/ z: kotlin.String): kotlin.Unit +public fun foo0002(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Number, /*2*/ z: kotlin.String): kotlin.Unit +public fun foo0002(/*0*/ x: kotlin.String, /*1*/ y: kotlin.Float, /*2*/ z: kotlin.Int): kotlin.Unit +public fun foo11(/*0*/ x: kotlin.collections.MutableSet>): kotlin.Unit +@kotlin.jvm.JvmName(name = "foo112") public fun foo11(/*0*/ x: kotlin.collections.MutableSet>): kotlin.Unit +@kotlin.jvm.JvmName(name = "foo111") public fun foo11(/*0*/ x: kotlin.collections.MutableSet>): kotlin.Unit +public fun main(): kotlin.Unit +public fun test(): kotlin.Unit +public fun twoBuilderLambdas(/*0*/ @kotlin.BuilderInference block: Foo.() -> kotlin.Unit, /*1*/ @kotlin.BuilderInference block2: Foo2.() -> kotlin.Unit): kotlin.Unit +public fun kotlin.Int.bar(): kotlin.Unit +@kotlin.jvm.JvmName(name = "bar1") public fun kotlin.String.bar(): kotlin.Unit +public fun kotlin.Int.foo0003(/*0*/ y: kotlin.Number, /*1*/ z: kotlin.String): kotlin.Unit +public fun kotlin.String.foo0003(/*0*/ y: kotlin.Float, /*1*/ z: kotlin.Int): kotlin.Unit +public fun Inv.foo2(): kotlin.Unit +@kotlin.jvm.JvmName(name = "foo21") public fun Inv.foo2(): kotlin.Unit + +public interface Foo { + public abstract fun add(/*0*/ x: K): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun get(): K + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public interface Foo2 { + public abstract fun entries(): kotlin.collections.MutableSet> + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public abstract fun get(): kotlin.collections.MutableSet> + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public abstract fun put(/*0*/ x: K, /*1*/ y: V): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class Inv { + public constructor Inv(/*0*/ x: K) + 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 +} + diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java index 5c4802b7e2b..28bf2992219 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticTestGenerated.java @@ -13950,6 +13950,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest { runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt47744.kt"); } + @Test + @TestMetadata("kt49828.kt") + public void testKt49828() throws Exception { + runTest("compiler/testData/diagnostics/tests/inference/builderInference/kt49828.kt"); + } + @Test @TestMetadata("kt49829.kt") public void testKt49829() throws Exception { diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/StubTypes.kt b/core/descriptors/src/org/jetbrains/kotlin/types/StubTypes.kt index 92098a45196..b2783661bc1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/StubTypes.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/StubTypes.kt @@ -7,10 +7,11 @@ package org.jetbrains.kotlin.types import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.types.checker.KotlinTypeRefiner +import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.model.StubTypeMarker class StubTypeForBuilderInference( - originalTypeVariable: TypeConstructor, + originalTypeVariable: NewTypeVariableConstructor, isMarkedNullable: Boolean, override val constructor: TypeConstructor = createConstructor(originalTypeVariable) ) : AbstractStubType(originalTypeVariable, isMarkedNullable), StubTypeMarker { @@ -26,7 +27,7 @@ class StubTypeForBuilderInference( } class StubTypeForTypeVariablesInSubtyping( - originalTypeVariable: TypeConstructor, + originalTypeVariable: NewTypeVariableConstructor, isMarkedNullable: Boolean, override val constructor: TypeConstructor = createConstructor(originalTypeVariable) ) : AbstractStubType(originalTypeVariable, isMarkedNullable), StubTypeMarker { @@ -40,7 +41,7 @@ class StubTypeForTypeVariablesInSubtyping( // This type is used as a replacement of type variables for provideDelegate resolve class StubTypeForProvideDelegateReceiver( - originalTypeVariable: TypeConstructor, + originalTypeVariable: NewTypeVariableConstructor, isMarkedNullable: Boolean, override val constructor: TypeConstructor = createConstructor(originalTypeVariable) ) : AbstractStubType(originalTypeVariable, isMarkedNullable) { @@ -52,7 +53,7 @@ class StubTypeForProvideDelegateReceiver( } } -abstract class AbstractStubType(val originalTypeVariable: TypeConstructor, override val isMarkedNullable: Boolean) : SimpleType() { +abstract class AbstractStubType(val originalTypeVariable: NewTypeVariableConstructor, override val isMarkedNullable: Boolean) : SimpleType() { override val memberScope = ErrorUtils.createErrorScope("Scope for stub type: $originalTypeVariable") override val arguments: List @@ -73,7 +74,7 @@ abstract class AbstractStubType(val originalTypeVariable: TypeConstructor, overr abstract fun materialize(newNullability: Boolean): AbstractStubType companion object { - fun createConstructor(originalTypeVariable: TypeConstructor) = + fun createConstructor(originalTypeVariable: NewTypeVariableConstructor) = ErrorUtils.createErrorTypeConstructor("Constructor for stub type: $originalTypeVariable") } } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt index c4a120adeb6..33fa686e6f8 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/utils.kt @@ -102,6 +102,6 @@ private fun TypeConstructor.debugInfo() = buildString { } } -interface NewTypeVariableConstructor { +interface NewTypeVariableConstructor : TypeConstructor { val originalTypeParameter: TypeParameterDescriptor? }