[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 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)
|
||||
|
||||
+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.addSubtypeConstraintIfCompatible
|
||||
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.tower.isSuccess
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
@@ -82,80 +81,49 @@ internal object CheckArguments : ResolutionPart {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun computeParameterTypes(
|
||||
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()
|
||||
}
|
||||
|
||||
// if expected type isn't function type, then may be it is Function<R>, Any or just `T`
|
||||
fun processLambdaArgument(
|
||||
kotlinCall: KotlinCall,
|
||||
csBuilder: ConstraintSystemBuilder,
|
||||
argument: LambdaKotlinCallArgument,
|
||||
expectedType: UnwrappedType
|
||||
): 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 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 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.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.ResultTypeResolver
|
||||
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.NotEnoughInformationForTypeParameter
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.returnTypeOrNothing
|
||||
@@ -220,6 +219,7 @@ class KotlinCallCompleter(
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if (c.hasContradiction) return true
|
||||
|
||||
@@ -240,14 +240,7 @@ class KotlinCallCompleter(
|
||||
break
|
||||
}
|
||||
c.fixVariable(variable, resultType)
|
||||
|
||||
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 false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
+28
-58
@@ -16,16 +16,16 @@
|
||||
|
||||
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.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewKotlinTypeChecker
|
||||
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.SmartList
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
private typealias Variable = VariableWithConstraints
|
||||
|
||||
@@ -57,6 +57,8 @@ class FixationOrderCalculator {
|
||||
* result type U depends-on all parameters types V of the corresponding lambda
|
||||
*
|
||||
* LAMBDA-RESULT
|
||||
* Since there is no separate type variables for lambda such edges removed for now
|
||||
*
|
||||
* V is a lambda result type variable,
|
||||
* V <: T constraint exists for V,
|
||||
* 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 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
|
||||
fun getCompletionOrder(topReturnType: UnwrappedType): List<NodeWithDirection> {
|
||||
setupDirections(topReturnType)
|
||||
|
||||
computeLambdaResultDependencyEdges()
|
||||
buildLambdaEdges()
|
||||
|
||||
return topologicalOrderWith0Priority().map { NodeWithDirection(it, directions[it] ?: ResolveDirection.UNKNOWN) }
|
||||
}
|
||||
|
||||
private fun computeLambdaResultDependencyEdges() {
|
||||
val resolvedLambdaArguments = c.lambdaArguments.associateBy({ it.argument }, { it })
|
||||
private fun buildLambdaEdges() {
|
||||
for (lambdaArgument in c.lambdaArguments) {
|
||||
if (lambdaArgument.analyzed) continue
|
||||
|
||||
for (variable in c.notFixedTypeVariables.values) {
|
||||
val lambdaResultVariable = variable.typeVariable.takeLambdaResultVariable() ?: continue
|
||||
val typeVariablesInReturnType = SmartList<Variable>()
|
||||
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) {
|
||||
val initialDirection = when (constraint.kind) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
for (returnTypeVariable in typeVariablesInReturnType) {
|
||||
lambdaEdges.getOrPut(returnTypeVariable) { LinkedHashSet() }.addAll(typeVariablesInParameters)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun UnwrappedType.findTypeVariables(to: MutableCollection<Variable>) = contains {
|
||||
c.notFixedTypeVariables[it.constructor]?.let { variable -> to.add(variable) }
|
||||
false
|
||||
}
|
||||
|
||||
private fun topologicalOrderWith0Priority(): List<Variable> {
|
||||
val handler = object : DFS.CollectingNodeHandler<Variable, Variable, LinkedHashSet<Variable>>(LinkedHashSet()) {
|
||||
override fun afterChildren(current: Variable) {
|
||||
// LAMBDA dependency edges should always be satisfied
|
||||
// Note that cyclic by lambda edges are possible
|
||||
result.addAll(getLambdaDependencies(current))
|
||||
|
||||
result.add(current)
|
||||
@@ -139,11 +132,9 @@ class FixationOrderCalculator {
|
||||
enterToNode(variableWithConstraints, direction)
|
||||
}
|
||||
for (resolvedLambdaArgument in c.lambdaArguments) {
|
||||
inner@ for (typeVariable in resolvedLambdaArgument.myTypeVariables) {
|
||||
if (typeVariable.kind == LambdaTypeVariable.Kind.RETURN_TYPE) continue@inner
|
||||
|
||||
c.notFixedTypeVariables[typeVariable.freshTypeConstructor]?.let {
|
||||
enterToNode(it, ResolveDirection.TO_SUBTYPE)
|
||||
inner@ for (inputType in resolvedLambdaArgument.inputTypes) {
|
||||
inputType.visitType(ResolveDirection.TO_SUBTYPE) { variableWithConstraints, direction ->
|
||||
enterToNode(variableWithConstraints, direction)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +163,6 @@ class FixationOrderCalculator {
|
||||
val constraintEdges =
|
||||
LinkedHashSet<Variable>().also { set ->
|
||||
getConstraintDependencies(variable, direction).mapTo(set) { it.variableWithConstraints }
|
||||
set.addAll(getLambdaResultDependencies(variable))
|
||||
}.toList().sortByTypeVariable()
|
||||
val lambdaEdges = getLambdaDependencies(variable).sortByTypeVariable()
|
||||
return constraintEdges + lambdaEdges
|
||||
@@ -211,28 +201,8 @@ class FixationOrderCalculator {
|
||||
!(direction == ResolveDirection.TO_SUBTYPE && constraint.kind == ConstraintKind.UPPER) &&
|
||||
!(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> {
|
||||
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 getLambdaDependencies(variable: Variable): List<Variable> = lambdaEdges[variable]?.toList() ?: emptyList()
|
||||
|
||||
private fun UnwrappedType.visitType(startDirection: ResolveDirection, action: (variable: Variable, direction: ResolveDirection) -> Unit) =
|
||||
when (this) {
|
||||
|
||||
-22
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
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.types.*
|
||||
import org.jetbrains.kotlin.types.checker.NewTypeVariableConstructor
|
||||
@@ -53,24 +52,3 @@ class TypeVariableFromCallableDescriptor(
|
||||
val originalTypeParameter: TypeParameterDescriptor,
|
||||
val call: KotlinCall? = null
|
||||
) : 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
|
||||
|
||||
import org.jetbrains.kotlin.builtins.createFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
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.types.SimpleType
|
||||
import org.jetbrains.kotlin.types.UnwrappedType
|
||||
@@ -30,8 +28,7 @@ import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||
sealed class ArgumentWithPostponeResolution {
|
||||
abstract val outerCall: KotlinCall
|
||||
abstract val argument: KotlinCallArgument
|
||||
abstract val myTypeVariables: Collection<NewTypeVariable>
|
||||
abstract val inputType: Collection<UnwrappedType> // parameters and implicit receiver
|
||||
abstract val inputTypes: Collection<UnwrappedType> // parameters and implicit receiver
|
||||
abstract val outputType: UnwrappedType?
|
||||
|
||||
var analyzed: Boolean = false
|
||||
@@ -40,7 +37,6 @@ sealed class ArgumentWithPostponeResolution {
|
||||
class ResolvedLambdaArgument(
|
||||
override val outerCall: KotlinCall,
|
||||
override val argument: LambdaKotlinCallArgument,
|
||||
override val myTypeVariables: Collection<LambdaTypeVariable>,
|
||||
val isSuspend: Boolean,
|
||||
val receiver: UnwrappedType?,
|
||||
val parameters: List<UnwrappedType>,
|
||||
@@ -48,7 +44,7 @@ class ResolvedLambdaArgument(
|
||||
) : ArgumentWithPostponeResolution() {
|
||||
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
|
||||
|
||||
lateinit var resultArguments: List<KotlinCallArgument>
|
||||
@@ -57,9 +53,9 @@ class ResolvedLambdaArgument(
|
||||
class ResolvedCallableReferenceArgument(
|
||||
override val outerCall: KotlinCall,
|
||||
override val argument: CallableReferenceKotlinCallArgument,
|
||||
override val myTypeVariables: List<NewTypeVariable>,
|
||||
val myTypeVariables: List<NewTypeVariable>,
|
||||
val callableResolutionCandidate: CallableReferenceCandidate
|
||||
) : ArgumentWithPostponeResolution() {
|
||||
override val inputType: Collection<UnwrappedType> get() = emptyList()
|
||||
override val inputTypes: Collection<UnwrappedType> get() = emptyList()
|
||||
override val outputType: UnwrappedType? = null
|
||||
}
|
||||
@@ -123,9 +123,9 @@ class TypeApproximator {
|
||||
|
||||
if (conf.flexible) {
|
||||
/**
|
||||
* Let inputType = L_1..U_1; resultType = L_2..U_2
|
||||
* We should create resultType such as inputType <: resultType.
|
||||
* It means that if A <: inputType, then A <: U_1. And, because inputType <: resultType,
|
||||
* Let inputTypes = L_1..U_1; resultType = L_2..U_2
|
||||
* We should create resultType such as inputTypes <: 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.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* 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