Add a constraint for nested call

if there are no bounds on variables in this call return type
This commit is contained in:
Svetlana Isakova
2015-06-27 17:19:20 +03:00
parent 1463ff7258
commit 179c5e3c3a
5 changed files with 60 additions and 11 deletions
@@ -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)
@@ -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)
@@ -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>>() }
}