[NI] Remove type variables for lambda arguments -- use existing instead.
This commit is contained in:
committed by
Mikhail Zarechenskiy
parent
ff6a28b64c
commit
3a25405088
+1
-1
@@ -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)
|
||||||
|
|||||||
+34
-66
@@ -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)
|
||||||
|
|
||||||
|
|||||||
+2
-9
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-58
@@ -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) {
|
||||||
|
|||||||
-22
@@ -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]"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-8
@@ -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.
|
||||||
|
|||||||
Reference in New Issue
Block a user