Add a constraint for nested call
if there are no bounds on variables in this call return type
This commit is contained in:
@@ -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<CallableDescriptor>
|
||||
val contextForArgument = cachedContext.replaceBindingTrace(context.trace)
|
||||
|
||||
+55
-2
@@ -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]
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
package n
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val <!UNUSED_VARIABLE!>a<!> = array(<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>array<!>())
|
||||
val <!UNUSED_VARIABLE!>a<!> = <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>array<!>(<!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>array<!>())
|
||||
val <!UNUSED_VARIABLE!>a0<!> : Array<Array<Int>> = array(array())
|
||||
val a1 = array(array<Int>())
|
||||
checkSubtype<Array<Array<Int>>>(a1)
|
||||
|
||||
Vendored
+1
-1
@@ -8,5 +8,5 @@ fun <T, C: Collection<T>> convert(src: Collection<T>, dest: C): C = throw Except
|
||||
fun test(l: List<Int>) {
|
||||
//todo should be inferred
|
||||
val r = convert(l, HashSet())
|
||||
checkSubtype<Collection<Int>>(r)
|
||||
r checkType { _<HashSet<Int>>() }
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ fun <T, C: Base<T>> convert(src: HS<T>, dest: C): C = throw Exception("$src $des
|
||||
fun test(l: HS<Int>) {
|
||||
//todo should be inferred
|
||||
val r = convert(l, HS())
|
||||
checkSubtype<Base<Int>>(r)
|
||||
r checkType { _<HS<Int>>() }
|
||||
}
|
||||
Reference in New Issue
Block a user