diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index c61593f9d4f..a06e16920ab 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -264,13 +264,9 @@ public class CallCompleter( expression: JetExpression, context: BasicCallResolutionContext ): OverloadResolutionResultsImpl<*>? { - if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null + val cachedData = getResolutionResultsCachedData(expression, context) ?: return null + val (cachedResolutionResults, cachedContext, tracing) = cachedData - val argumentCall = expression.getCall(context.trace.getBindingContext()) ?: return null - - val cachedDataForCall = context.resolutionResultsCache[argumentCall] ?: return null - - val (cachedResolutionResults, cachedContext, tracing) = cachedDataForCall @suppress("UNCHECKED_CAST") val cachedResults = cachedResolutionResults as OverloadResolutionResultsImpl val contextForArgument = cachedContext.replaceBindingTrace(context.trace) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index b784dcb9953..cbde47b02c5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -29,12 +29,15 @@ import org.jetbrains.kotlin.resolve.calls.ArgumentTypeResolver.getLastElementDep import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SHAPE_FUNCTION_ARGUMENTS import org.jetbrains.kotlin.resolve.calls.CallResolverUtil.getEffectiveExpectedType +import org.jetbrains.kotlin.resolve.calls.callUtil.getCall import org.jetbrains.kotlin.resolve.calls.context.CallCandidateResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext +import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl +import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus @@ -140,11 +143,54 @@ class GenericCandidateResolver( val typeInfoForCall = argumentTypeResolver.getArgumentTypeInfo(argumentExpression, newContext, resolveFunctionArgumentBodies) context.candidateCall.getDataFlowInfoForArguments().updateInfo(valueArgument, typeInfoForCall.dataFlowInfo) + val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex()) + + if (addConstraintForNestedCall(argumentExpression, constraintPosition, constraintSystem, newContext, effectiveExpectedType)) return + val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument)) - constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.getIndex())) + constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, constraintPosition) } - private fun updateResultTypeForSmartCasts(type: JetType?, argumentExpression: JetExpression?, context: ResolutionContext<*>): JetType? { + private fun addConstraintForNestedCall( + argumentExpression: JetExpression?, + constraintPosition: ConstraintPosition, + constraintSystem: ConstraintSystem, + context: CallCandidateResolutionContext<*>, + effectiveExpectedType: JetType + ): Boolean { + val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults + if (resolutionResults == null || !resolutionResults.isSingleResult()) return false + + val resultingCall = resolutionResults.getResultingCall() + if (resultingCall.isCompleted()) return false + + val argumentConstraintSystem = resultingCall.getConstraintSystem() as ConstraintSystemImpl? ?: return false + + val candidateDescriptor = resultingCall.getCandidateDescriptor() + val returnType = candidateDescriptor.getReturnType() ?: return false + + val nestedTypeVariables = with (argumentConstraintSystem) { + returnType.getNestedTypeVariables() + } + // we add an additional type variable only if no information is inferred for it. + // otherwise we add currently inferred return type as before + if (nestedTypeVariables.any { argumentConstraintSystem.getTypeBounds(it).bounds.isNotEmpty() }) return false + + val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidateDescriptor) + val conversion = candidateDescriptor.getTypeParameters().zip(candidateWithFreshVariables.getTypeParameters()).toMap() + + val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull() + constraintSystem.registerTypeVariables(freshVariables, { Variance.INVARIANT }, external = true) + + constraintSystem.addSubtypeConstraint(candidateWithFreshVariables.getReturnType(), effectiveExpectedType, constraintPosition) + return true + } + + private fun updateResultTypeForSmartCasts( + type: JetType?, + argumentExpression: JetExpression?, + context: ResolutionContext<*> + ): JetType? { val deparenthesizedArgument = getLastElementDeparenthesized(argumentExpression, context) if (deparenthesizedArgument == null || type == null) return type @@ -227,4 +273,11 @@ class GenericCandidateResolver( val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, position) } +} + +fun getResolutionResultsCachedData(expression: JetExpression?, context: ResolutionContext<*>): ResolutionResultsCache.CachedData? { + if (!ExpressionTypingUtils.dependsOnExpectedType(expression)) return null + val argumentCall = expression?.getCall(context.trace.getBindingContext()) ?: return null + + return context.resolutionResultsCache[argumentCall] } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inference/regressions/kt2200.kt b/compiler/testData/diagnostics/tests/inference/regressions/kt2200.kt index ba518ebc253..d3e473eedb8 100644 --- a/compiler/testData/diagnostics/tests/inference/regressions/kt2200.kt +++ b/compiler/testData/diagnostics/tests/inference/regressions/kt2200.kt @@ -4,7 +4,7 @@ package n fun main(args: Array) { - val a = array(array()) + val a = array(array()) val a0 : Array> = array(array()) val a1 = array(array()) checkSubtype>>(a1) diff --git a/compiler/testData/diagnostics/tests/inference/upperBounds/conflictingSubstitutionsFromUpperBound.kt b/compiler/testData/diagnostics/tests/inference/upperBounds/conflictingSubstitutionsFromUpperBound.kt index 062a40d549d..0fe2041a8e8 100644 --- a/compiler/testData/diagnostics/tests/inference/upperBounds/conflictingSubstitutionsFromUpperBound.kt +++ b/compiler/testData/diagnostics/tests/inference/upperBounds/conflictingSubstitutionsFromUpperBound.kt @@ -8,5 +8,5 @@ fun > convert(src: Collection, dest: C): C = throw Except fun test(l: List) { //todo should be inferred val r = convert(l, HashSet()) - checkSubtype>(r) + r checkType { _>() } } diff --git a/compiler/testData/diagnostics/tests/platformTypes/inference.kt b/compiler/testData/diagnostics/tests/platformTypes/inference.kt index bc322da00d1..f6818460b8b 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/inference.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/inference.kt @@ -21,5 +21,5 @@ fun > convert(src: HS, dest: C): C = throw Exception("$src $des fun test(l: HS) { //todo should be inferred val r = convert(l, HS()) - checkSubtype>(r) + r checkType { _>() } } \ No newline at end of file