[NI] Remove type variables for lambda arguments -- use existing instead.

This commit is contained in:
Stanislav Erokhin
2017-05-19 16:31:52 +03:00
committed by Mikhail Zarechenskiy
parent ff6a28b64c
commit 3a25405088
7 changed files with 73 additions and 168 deletions
@@ -77,7 +77,7 @@ class KotlinResolutionCallbacksImpl(
val approximatesExpectedType = typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType val approximatesExpectedType = typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType
val actualContext = outerCallContext.replaceBindingTrace(trace). val actualContext = outerCallContext.replaceBindingTrace(trace).
replaceContextDependency(ContextDependency.DEPENDENT).replaceExpectedType(approximatesExpectedType) replaceContextDependency(if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT).replaceExpectedType(approximatesExpectedType)
val functionTypeInfo = expressionTypingServices.getTypeInfo(expression, actualContext) val functionTypeInfo = expressionTypingServices.getTypeInfo(expression, actualContext)
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.resolve.calls.components.CreateDescriptorWithFreshTy
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilder
import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible import org.jetbrains.kotlin.resolve.calls.inference.addSubtypeConstraintIfCompatible
import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ArgumentConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
import org.jetbrains.kotlin.resolve.calls.model.* import org.jetbrains.kotlin.resolve.calls.model.*
import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.resolve.calls.tower.isSuccess
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
@@ -82,80 +81,49 @@ internal object CheckArguments : ResolutionPart {
} }
} }
inline fun computeParameterTypes( // if expected type isn't function type, then may be it is Function<R>, Any or just `T`
argument: LambdaKotlinCallArgument,
expectedType: UnwrappedType,
createFreshType: () -> UnwrappedType
): List<UnwrappedType> {
argument.parametersTypes?.map { it ?: createFreshType() } ?.let { return it }
if (expectedType.isBuiltinFunctionalType) {
return expectedType.getValueParameterTypesFromFunctionType().map { createFreshType() }
}
// if expected type is non-functional type and there is no declared parameters
return emptyList()
}
inline fun computeReceiver(
argument: LambdaKotlinCallArgument,
expectedType: UnwrappedType,
createFreshType: () -> UnwrappedType
) : UnwrappedType? {
if (argument is FunctionExpression) return argument.receiverType
if (expectedType.isBuiltinExtensionFunctionalType) return createFreshType()
return null
}
inline fun computeReturnType(
argument: LambdaKotlinCallArgument,
createFreshType: () -> UnwrappedType
) : UnwrappedType {
if (argument is FunctionExpression) return argument.receiverType ?: createFreshType()
return createFreshType()
}
fun processLambdaArgument( fun processLambdaArgument(
kotlinCall: KotlinCall, kotlinCall: KotlinCall,
csBuilder: ConstraintSystemBuilder, csBuilder: ConstraintSystemBuilder,
argument: LambdaKotlinCallArgument, argument: LambdaKotlinCallArgument,
expectedType: UnwrappedType expectedType: UnwrappedType
): KotlinCallDiagnostic? { ): KotlinCallDiagnostic? {
// initial checks
if (expectedType.isBuiltinFunctionalType) {
val expectedParameterCount = expectedType.getValueParameterTypesFromFunctionType().size
argument.parametersTypes?.size?.let {
if (expectedParameterCount != it) return ExpectedLambdaParametersCountMismatch(argument, expectedParameterCount, it)
}
if (argument is FunctionExpression) {
if (argument.receiverType != null && !expectedType.isBuiltinExtensionFunctionalType) return UnexpectedReceiver(argument)
if (argument.receiverType == null && expectedType.isBuiltinExtensionFunctionalType) return MissingReceiver(argument)
}
}
val builtIns = expectedType.builtIns val builtIns = expectedType.builtIns
val freshVariables = SmartList<LambdaTypeVariable>()
val receiver = computeReceiver(argument, expectedType) {
LambdaTypeVariable(argument, LambdaTypeVariable.Kind.RECEIVER, builtIns).apply { freshVariables.add(this) }.defaultType
}
val parameters = computeParameterTypes(argument, expectedType) {
LambdaTypeVariable(argument, LambdaTypeVariable.Kind.PARAMETER, builtIns).apply { freshVariables.add(this) }.defaultType
}
val returnType = computeReturnType(argument) {
LambdaTypeVariable(argument, LambdaTypeVariable.Kind.RETURN_TYPE, builtIns).apply { freshVariables.add(this) }.defaultType
}
val isSuspend = expectedType.isSuspendFunctionType val isSuspend = expectedType.isSuspendFunctionType
val resolvedArgument = ResolvedLambdaArgument(kotlinCall, argument, freshVariables, isSuspend, receiver, parameters, returnType)
freshVariables.forEach(csBuilder::registerVariable) val receiverType: UnwrappedType? // null means that there is no receiver
val parameters: List<UnwrappedType>
val returnType: UnwrappedType
if (expectedType.isBuiltinFunctionalType) {
receiverType = if (argument is FunctionExpression) argument.receiverType else expectedType.getReceiverTypeFromFunctionType()?.unwrap()
val expectedParameters = expectedType.getValueParameterTypesFromFunctionType()
if (argument.parametersTypes != null) {
parameters = argument.parametersTypes!!.mapIndexed {
index, type ->
type ?: expectedParameters.getOrNull(index)?.type?.unwrap() ?: builtIns.anyType
}
}
else {
// lambda without explicit parameters: { }
parameters = expectedParameters.map { it.type.unwrap() }
}
returnType = (argument as? FunctionExpression)?.returnType ?: expectedType.getReturnTypeFromFunctionType().unwrap()
}
else {
val isFunctionSupertype = KotlinBuiltIns.isNotNullOrNullableFunctionSupertype(expectedType)
receiverType = (argument as? FunctionExpression)?.receiverType
parameters = argument.parametersTypes?.map { it ?: builtIns.nothingType } ?: emptyList()
returnType = (argument as? FunctionExpression)?.returnType ?:
expectedType.arguments.singleOrNull()?.type?.unwrap()?.takeIf { isFunctionSupertype } ?:
builtIns.nullableAnyType
// what about case where expected type is type variable? In old TY such cases was not supported. => do nothing for now. todo design
}
val resolvedArgument = ResolvedLambdaArgument(kotlinCall, argument, isSuspend, receiverType, parameters, returnType)
csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument)) csBuilder.addSubtypeConstraint(resolvedArgument.type, expectedType, ArgumentConstraintPosition(argument))
csBuilder.addLambdaArgument(resolvedArgument) csBuilder.addLambdaArgument(resolvedArgument)
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.resolve.calls.inference.components.FixationOrderCalc
import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor import org.jetbrains.kotlin.resolve.calls.inference.components.NewTypeSubstitutor
import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver import org.jetbrains.kotlin.resolve.calls.inference.components.ResultTypeResolver
import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.model.ExpectedTypeConstraintPosition
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter import org.jetbrains.kotlin.resolve.calls.inference.model.NotEnoughInformationForTypeParameter
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
@@ -220,6 +219,7 @@ class KotlinCallCompleter(
} }
// true if it is the end (happy or not) // true if it is the end (happy or not)
// every step we fix type variable or analyzeLambda
private fun SimpleKotlinResolutionCandidate.oneStepToEndOrLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks): Boolean { private fun SimpleKotlinResolutionCandidate.oneStepToEndOrLambda(c: Context, resolutionCallbacks: KotlinResolutionCallbacks): Boolean {
if (c.hasContradiction) return true if (c.hasContradiction) return true
@@ -240,14 +240,7 @@ class KotlinCallCompleter(
break break
} }
c.fixVariable(variable, resultType) c.fixVariable(variable, resultType)
return false
if (variable is LambdaTypeVariable) {
val resolvedLambda = c.lambdaArguments.find { it.argument == variable.lambdaArgument } ?: return true
if (canWeAnalyzeIt(c, resolvedLambda)) {
analyzeLambda(c, resolutionCallbacks, callContext, kotlinCall, resolvedLambda)
return false
}
}
} }
return true return true
} }
@@ -16,16 +16,16 @@
package org.jetbrains.kotlin.resolve.calls.inference.components package org.jetbrains.kotlin.resolve.calls.inference.components
import org.jetbrains.kotlin.resolve.calls.inference.model.* import org.jetbrains.kotlin.resolve.calls.inference.model.Constraint
import org.jetbrains.kotlin.resolve.calls.inference.model.ConstraintKind
import org.jetbrains.kotlin.resolve.calls.inference.model.VariableWithConstraints
import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument import org.jetbrains.kotlin.resolve.calls.model.ResolvedLambdaArgument
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
import org.jetbrains.kotlin.types.checker.isIntersectionType import org.jetbrains.kotlin.types.checker.isIntersectionType
import org.jetbrains.kotlin.types.typeUtil.contains
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.SmartList import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
import kotlin.collections.HashMap
private typealias Variable = VariableWithConstraints private typealias Variable = VariableWithConstraints
@@ -57,6 +57,8 @@ class FixationOrderCalculator {
* result type U depends-on all parameters types V of the corresponding lambda * result type U depends-on all parameters types V of the corresponding lambda
* *
* LAMBDA-RESULT * LAMBDA-RESULT
* Since there is no separate type variables for lambda such edges removed for now
*
* V is a lambda result type variable, * V is a lambda result type variable,
* V <: T constraint exists for V, * V <: T constraint exists for V,
* U is a constituent type of T in position matching approximation direction for U * U is a constituent type of T in position matching approximation direction for U
@@ -73,54 +75,45 @@ class FixationOrderCalculator {
private class DependencyGraph(val c: Context) { private class DependencyGraph(val c: Context) {
private val directions = HashMap<Variable, ResolveDirection>() private val directions = HashMap<Variable, ResolveDirection>()
private val lambdaResultDependencyEdges = HashMap<Variable, MutableList<Variable>>() private val lambdaEdges = HashMap<Variable, MutableSet<Variable>>()
// first in the list -- first fix // first in the list -- first fix
fun getCompletionOrder(topReturnType: UnwrappedType): List<NodeWithDirection> { fun getCompletionOrder(topReturnType: UnwrappedType): List<NodeWithDirection> {
setupDirections(topReturnType) setupDirections(topReturnType)
computeLambdaResultDependencyEdges() buildLambdaEdges()
return topologicalOrderWith0Priority().map { NodeWithDirection(it, directions[it] ?: ResolveDirection.UNKNOWN) } return topologicalOrderWith0Priority().map { NodeWithDirection(it, directions[it] ?: ResolveDirection.UNKNOWN) }
} }
private fun computeLambdaResultDependencyEdges() { private fun buildLambdaEdges() {
val resolvedLambdaArguments = c.lambdaArguments.associateBy({ it.argument }, { it }) for (lambdaArgument in c.lambdaArguments) {
if (lambdaArgument.analyzed) continue
for (variable in c.notFixedTypeVariables.values) { val typeVariablesInReturnType = SmartList<Variable>()
val lambdaResultVariable = variable.typeVariable.takeLambdaResultVariable() ?: continue lambdaArgument.returnType.findTypeVariables(typeVariablesInReturnType)
val lambdaArgument = lambdaResultVariable.lambdaArgument if (typeVariablesInReturnType.isEmpty()) continue // optimization
if (resolvedLambdaArguments[lambdaArgument]?.analyzed ?: false) continue val typeVariablesInParameters = SmartList<Variable>()
lambdaArgument.inputTypes.forEach { it.findTypeVariables(typeVariablesInParameters) }
for (constraint in variable.constraints) { for (returnTypeVariable in typeVariablesInReturnType) {
val initialDirection = when (constraint.kind) { lambdaEdges.getOrPut(returnTypeVariable) { LinkedHashSet() }.addAll(typeVariablesInParameters)
ConstraintKind.LOWER -> ResolveDirection.TO_SUBTYPE
ConstraintKind.UPPER -> ResolveDirection.TO_SUPERTYPE
ConstraintKind.EQUALITY -> ResolveDirection.UNKNOWN // ???
}
constraint.type.visitType(initialDirection) { constituentVariable, direction ->
val constituentVariableDirection = directions.getOrElse(constituentVariable) { ResolveDirection.UNKNOWN }
val constituentTypeVariable = constituentVariable.typeVariable
if (constituentTypeVariable is LambdaTypeVariable) {
if (constituentTypeVariable.lambdaArgument == lambdaArgument) return@visitType
}
if (direction == ResolveDirection.UNKNOWN || direction == constituentVariableDirection) {
lambdaResultDependencyEdges.getOrPut(constituentVariable) { SmartList() }.add(variable)
}
}
} }
} }
} }
private fun UnwrappedType.findTypeVariables(to: MutableCollection<Variable>) = contains {
c.notFixedTypeVariables[it.constructor]?.let { variable -> to.add(variable) }
false
}
private fun topologicalOrderWith0Priority(): List<Variable> { private fun topologicalOrderWith0Priority(): List<Variable> {
val handler = object : DFS.CollectingNodeHandler<Variable, Variable, LinkedHashSet<Variable>>(LinkedHashSet()) { val handler = object : DFS.CollectingNodeHandler<Variable, Variable, LinkedHashSet<Variable>>(LinkedHashSet()) {
override fun afterChildren(current: Variable) { override fun afterChildren(current: Variable) {
// LAMBDA dependency edges should always be satisfied // LAMBDA dependency edges should always be satisfied
// Note that cyclic by lambda edges are possible
result.addAll(getLambdaDependencies(current)) result.addAll(getLambdaDependencies(current))
result.add(current) result.add(current)
@@ -139,11 +132,9 @@ class FixationOrderCalculator {
enterToNode(variableWithConstraints, direction) enterToNode(variableWithConstraints, direction)
} }
for (resolvedLambdaArgument in c.lambdaArguments) { for (resolvedLambdaArgument in c.lambdaArguments) {
inner@ for (typeVariable in resolvedLambdaArgument.myTypeVariables) { inner@ for (inputType in resolvedLambdaArgument.inputTypes) {
if (typeVariable.kind == LambdaTypeVariable.Kind.RETURN_TYPE) continue@inner inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
enterToNode(variableWithConstraints, direction)
c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.let {
enterToNode(it, ResolveDirection.TO_SUBTYPE)
} }
} }
} }
@@ -172,7 +163,6 @@ class FixationOrderCalculator {
val constraintEdges = val constraintEdges =
LinkedHashSet<Variable>().also { set -> LinkedHashSet<Variable>().also { set ->
getConstraintDependencies(variable, direction).mapTo(set) { it.variableWithConstraints } getConstraintDependencies(variable, direction).mapTo(set) { it.variableWithConstraints }
set.addAll(getLambdaResultDependencies(variable))
}.toList().sortByTypeVariable() }.toList().sortByTypeVariable()
val lambdaEdges = getLambdaDependencies(variable).sortByTypeVariable() val lambdaEdges = getLambdaDependencies(variable).sortByTypeVariable()
return constraintEdges + lambdaEdges return constraintEdges + lambdaEdges
@@ -211,28 +201,8 @@ class FixationOrderCalculator {
!(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) && !(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) &&
!(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER) !(direction == ResolveDirection.TO_SUPERTYPE && constraint.kind == ConstraintKind.LOWER)
private fun getLambdaResultDependencies(variable: Variable): List<Variable> =
lambdaResultDependencyEdges.getOrElse(variable) { emptyList() }
private fun getLambdaDependencies(variable: Variable): List<Variable> { private fun getLambdaDependencies(variable: Variable): List<Variable> = lambdaEdges[variable]?.toList() ?: emptyList()
val typeVariable = variable.typeVariable.takeLambdaResultVariable() ?: return emptyList()
val resolvedLambdaArgument = c.lambdaArguments.find { it.argument == typeVariable.lambdaArgument } ?:
error("Missing resolved lambda argument for ${typeVariable.lambdaArgument}")
return buildVariablesList {
for (lambdaTypeVariable in resolvedLambdaArgument.myTypeVariables) {
if (lambdaTypeVariable.kind == LambdaTypeVariable.Kind.RETURN_TYPE) continue
addIfNotNull(c.notFixedTypeVariables[lambdaTypeVariable.freshTypeConstructor])
}
}
}
private inline fun buildVariablesList(builder: MutableList<Variable>.() -> Unit): List<Variable> =
SmartList<Variable>().apply(builder).toList()
private fun NewTypeVariable.takeLambdaResultVariable(): LambdaTypeVariable? =
if (this is LambdaTypeVariable && this.kind == LambdaTypeVariable.Kind.RETURN_TYPE) this else null
private fun UnwrappedType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) = private fun UnwrappedType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) =
when (this) { when (this) {
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.model.KotlinCall import org.jetbrains.kotlin.resolve.calls.model.KotlinCall
import org.jetbrains.kotlin.resolve.calls.model.LambdaKotlinCallArgument
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
@@ -53,24 +52,3 @@ class TypeVariableFromCallableDescriptor(
val originalTypeParameter: TypeParameterDescriptor, val originalTypeParameter: TypeParameterDescriptor,
val call: KotlinCall? = null val call: KotlinCall? = null
) : NewTypeVariable(originalTypeParameter.builtIns, originalTypeParameter.name.identifier) ) : NewTypeVariable(originalTypeParameter.builtIns, originalTypeParameter.name.identifier)
class LambdaTypeVariable(
val lambdaArgument: LambdaKotlinCallArgument,
val kind: Kind,
builtIns: KotlinBuiltIns
) : NewTypeVariable(builtIns, createDebugName(lambdaArgument, kind)) {
enum class Kind {
RECEIVER,
PARAMETER,
RETURN_TYPE
}
}
private fun createDebugName(lambdaArgument: LambdaKotlinCallArgument, kind: LambdaTypeVariable.Kind): String {
val text = lambdaArgument.toString().let { it.substring(0..(Math.min(20, it.lastIndex))) }
return when (kind) {
LambdaTypeVariable.Kind.RECEIVER -> "Receiver[$text]"
LambdaTypeVariable.Kind.PARAMETER -> "Parameter[$text]"
LambdaTypeVariable.Kind.RETURN_TYPE -> "Result[$text]"
}
}
@@ -17,10 +17,8 @@
package org.jetbrains.kotlin.resolve.calls.model package org.jetbrains.kotlin.resolve.calls.model
import org.jetbrains.kotlin.builtins.createFunctionType import org.jetbrains.kotlin.builtins.createFunctionType
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate import org.jetbrains.kotlin.resolve.calls.components.CallableReferenceCandidate
import org.jetbrains.kotlin.resolve.calls.inference.model.LambdaTypeVariable
import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable import org.jetbrains.kotlin.resolve.calls.inference.model.NewTypeVariable
import org.jetbrains.kotlin.types.SimpleType import org.jetbrains.kotlin.types.SimpleType
import org.jetbrains.kotlin.types.UnwrappedType import org.jetbrains.kotlin.types.UnwrappedType
@@ -30,8 +28,7 @@ import org.jetbrains.kotlin.types.typeUtil.builtIns
sealed class ArgumentWithPostponeResolution { sealed class ArgumentWithPostponeResolution {
abstract val outerCall: KotlinCall abstract val outerCall: KotlinCall
abstract val argument: KotlinCallArgument abstract val argument: KotlinCallArgument
abstract val myTypeVariables: Collection<NewTypeVariable> abstract val inputTypes: Collection<UnwrappedType> // parameters and implicit receiver
abstract val inputType: Collection<UnwrappedType> // parameters and implicit receiver
abstract val outputType: UnwrappedType? abstract val outputType: UnwrappedType?
var analyzed: Boolean = false var analyzed: Boolean = false
@@ -40,7 +37,6 @@ sealed class ArgumentWithPostponeResolution {
class ResolvedLambdaArgument( class ResolvedLambdaArgument(
override val outerCall: KotlinCall, override val outerCall: KotlinCall,
override val argument: LambdaKotlinCallArgument, override val argument: LambdaKotlinCallArgument,
override val myTypeVariables: Collection<LambdaTypeVariable>,
val isSuspend: Boolean, val isSuspend: Boolean,
val receiver: UnwrappedType?, val receiver: UnwrappedType?,
val parameters: List<UnwrappedType>, val parameters: List<UnwrappedType>,
@@ -48,7 +44,7 @@ class ResolvedLambdaArgument(
) : ArgumentWithPostponeResolution() { ) : ArgumentWithPostponeResolution() {
val type: SimpleType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiver, parameters, null, returnType, isSuspend) // todo support annotations val type: SimpleType = createFunctionType(returnType.builtIns, Annotations.EMPTY, receiver, parameters, null, returnType, isSuspend) // todo support annotations
override val inputType: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters override val inputTypes: Collection<UnwrappedType> get() = receiver?.let { parameters + it } ?: parameters
override val outputType: UnwrappedType get() = returnType override val outputType: UnwrappedType get() = returnType
lateinit var resultArguments: List<KotlinCallArgument> lateinit var resultArguments: List<KotlinCallArgument>
@@ -57,9 +53,9 @@ class ResolvedLambdaArgument(
class ResolvedCallableReferenceArgument( class ResolvedCallableReferenceArgument(
override val outerCall: KotlinCall, override val outerCall: KotlinCall,
override val argument: CallableReferenceKotlinCallArgument, override val argument: CallableReferenceKotlinCallArgument,
override val myTypeVariables: List<NewTypeVariable>, val myTypeVariables: List<NewTypeVariable>,
val callableResolutionCandidate: CallableReferenceCandidate val callableResolutionCandidate: CallableReferenceCandidate
) : ArgumentWithPostponeResolution() { ) : ArgumentWithPostponeResolution() {
override val inputType: Collection<UnwrappedType> get() = emptyList() override val inputTypes: Collection<UnwrappedType> get() = emptyList()
override val outputType: UnwrappedType? = null override val outputType: UnwrappedType? = null
} }
@@ -123,9 +123,9 @@ class TypeApproximator {
if (conf.flexible) { if (conf.flexible) {
/** /**
* Let inputType = L_1..U_1; resultType = L_2..U_2 * Let inputTypes = L_1..U_1; resultType = L_2..U_2
* We should create resultType such as inputType <: resultType. * We should create resultType such as inputTypes <: resultType.
* It means that if A <: inputType, then A <: U_1. And, because inputType <: resultType, * It means that if A <: inputTypes, then A <: U_1. And, because inputTypes <: resultType,
* A <: resultType => A <: U_2. I.e. for every type A such A <: U_1, A <: U_2 => U_1 <: U_2. * A <: resultType => A <: U_2. I.e. for every type A such A <: U_1, A <: U_2 => U_1 <: U_2.
* *
* Similar for L_1 <: L_2: Let B : resultType <: B. L_2 <: B and L_1 <: B. * Similar for L_1 <: L_2: Let B : resultType <: B. L_2 <: B and L_1 <: B.
@@ -138,7 +138,7 @@ class TypeApproximator {
/** /**
* If C <: L..U then C <: L. * If C <: L..U then C <: L.
* inputType.lower <: lowerResult => inputType.lower <: lowerResult?.lowerIfFlexible() * inputTypes.lower <: lowerResult => inputTypes.lower <: lowerResult?.lowerIfFlexible()
* i.e. this type is correct. We use this type, because this type more flexible. * i.e. this type is correct. We use this type, because this type more flexible.
* *
* If U_1 <: U_2.lower .. U_2.upper, then we know only that U_1 <: U_2.upper. * If U_1 <: U_2.lower .. U_2.upper, then we know only that U_1 <: U_2.upper.