Don't use originalToVariableSubstitutor in supertype constraints
This commit is contained in:
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemCompleter;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.TypeVariableKt;
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
@@ -36,9 +37,7 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.validation.OperatorValidator;
|
||||
import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator;
|
||||
import org.jetbrains.kotlin.types.DeferredType;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.*;
|
||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices;
|
||||
@@ -369,7 +368,13 @@ public class DelegatedPropertyResolver {
|
||||
FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor();
|
||||
KotlinType returnTypeOfGetMethod = descriptor.getReturnType();
|
||||
if (returnTypeOfGetMethod != null && !TypeUtils.noExpectedType(expectedType)) {
|
||||
constraintSystem.addSupertypeConstraint(expectedType, returnTypeOfGetMethod, FROM_COMPLETER.position());
|
||||
TypeSubstitutor substitutor =
|
||||
constraintSystem.getTypeVariableSubstitutors().get(TypeVariableKt.toHandle(resolvedCall.getCall()));
|
||||
assert substitutor != null : "No substitutor in the system for call: " + resolvedCall.getCall();
|
||||
KotlinType returnTypeInSystem = substitutor.substitute(returnTypeOfGetMethod, Variance.INVARIANT);
|
||||
if (returnTypeInSystem != null) {
|
||||
constraintSystem.addSupertypeConstraint(expectedType, returnTypeInSystem, FROM_COMPLETER.position());
|
||||
}
|
||||
}
|
||||
addConstraintForThisValue(constraintSystem, descriptor);
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.InferenceErrorData
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.*
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.filterConstraintsOut
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.toHandle
|
||||
import org.jetbrains.kotlin.resolve.calls.model.*
|
||||
import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResultsImpl
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
@@ -44,6 +45,7 @@ import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator
|
||||
import org.jetbrains.kotlin.types.ErrorUtils
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
|
||||
import java.util.*
|
||||
|
||||
@@ -139,6 +141,14 @@ public class CallCompleter(
|
||||
expectedType: KotlinType,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
val returnType = candidateDescriptor.returnType
|
||||
|
||||
fun ConstraintSystem.Builder.returnTypeInSystem(): KotlinType? =
|
||||
returnType?.let {
|
||||
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
|
||||
substitutor.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
fun updateSystemIfNeeded(buildSystemWithAdditionalConstraints: (ConstraintSystem.Builder) -> ConstraintSystem?) {
|
||||
val system = buildSystemWithAdditionalConstraints(constraintSystem!!.toBuilder())
|
||||
if (system != null) {
|
||||
@@ -146,11 +156,14 @@ public class CallCompleter(
|
||||
}
|
||||
}
|
||||
|
||||
val returnType = getCandidateDescriptor().getReturnType()
|
||||
if (returnType != null && !TypeUtils.noExpectedType(expectedType)) {
|
||||
updateSystemIfNeeded { builder ->
|
||||
builder.addSupertypeConstraint(expectedType, returnType, EXPECTED_TYPE_POSITION.position())
|
||||
builder.build()
|
||||
val returnTypeInSystem = builder.returnTypeInSystem()
|
||||
if (returnTypeInSystem != null) {
|
||||
builder.addSupertypeConstraint(expectedType, returnTypeInSystem, EXPECTED_TYPE_POSITION.position())
|
||||
builder.build()
|
||||
}
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,9 +182,13 @@ public class CallCompleter(
|
||||
|
||||
if (returnType != null && expectedType === TypeUtils.UNIT_EXPECTED_TYPE) {
|
||||
updateSystemIfNeeded { builder ->
|
||||
builder.addSupertypeConstraint(builtIns.getUnitType(), returnType, EXPECTED_TYPE_POSITION.position())
|
||||
val system = builder.build()
|
||||
if (system.status.isSuccessful()) system else null
|
||||
val returnTypeInSystem = builder.returnTypeInSystem()
|
||||
if (returnTypeInSystem != null) {
|
||||
builder.addSupertypeConstraint(builtIns.getUnitType(), returnTypeInSystem, EXPECTED_TYPE_POSITION.position())
|
||||
val system = builder.build()
|
||||
if (system.status.isSuccessful()) system else null
|
||||
}
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -86,7 +86,14 @@ interface ConstraintSystem {
|
||||
* For example, for `fun <T> create(): T` to infer `T` in invocation `val i: Int = create()`
|
||||
* the constraint "Int is a supertype of T" should be generated where T is a subject type, and Int is a constraining type.
|
||||
*/
|
||||
fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition)
|
||||
fun addSupertypeConstraint(constrainingType: KotlinType, subjectType: KotlinType, constraintPosition: ConstraintPosition)
|
||||
|
||||
/**
|
||||
* For each call for which type variables were registered, a type substitutor is stored in this map which maps
|
||||
* type parameter descriptors of the candidate descriptor of that call -> type variables of the system.
|
||||
* Those are the same substitutors that are returned by [registerTypeVariables] at the time of variable registration.
|
||||
*/
|
||||
val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
|
||||
|
||||
fun fixVariables()
|
||||
|
||||
|
||||
+18
-7
@@ -53,6 +53,8 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
|
||||
internal val initialConstraints = ArrayList<Constraint>()
|
||||
internal val descriptorToVariable = LinkedHashMap<TypeParameterDescriptor, TypeVariable>()
|
||||
|
||||
override val typeVariableSubstitutors = LinkedHashMap<CallHandle, TypeSubstitutor>()
|
||||
|
||||
private val descriptorToVariableSubstitutor: TypeSubstitutor by lazy {
|
||||
TypeSubstitutor.create(object : TypeConstructorSubstitution() {
|
||||
override fun get(key: TypeConstructor): TypeProjection? {
|
||||
@@ -64,10 +66,18 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
|
||||
})
|
||||
}
|
||||
|
||||
private fun storeSubstitutor(call: CallHandle, substitutor: TypeSubstitutor): TypeSubstitutor {
|
||||
if (typeVariableSubstitutors.containsKey(call)) {
|
||||
throw IllegalStateException("Type variables for the same call can be registered only once: $call")
|
||||
}
|
||||
typeVariableSubstitutors[call] = substitutor
|
||||
return substitutor
|
||||
}
|
||||
|
||||
override fun registerTypeVariables(
|
||||
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
|
||||
): TypeSubstitutor {
|
||||
if (typeParameters.isEmpty()) return TypeSubstitutor.EMPTY
|
||||
if (typeParameters.isEmpty()) return storeSubstitutor(call, TypeSubstitutor.EMPTY)
|
||||
|
||||
val typeVariables = if (external) {
|
||||
typeParameters.map {
|
||||
@@ -98,9 +108,9 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
|
||||
}
|
||||
}
|
||||
|
||||
return TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap(
|
||||
return storeSubstitutor(call, TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap(
|
||||
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
|
||||
))
|
||||
)))
|
||||
}
|
||||
|
||||
private fun KotlinType.isProper() = !TypeUtils.containsSpecialType(this) {
|
||||
@@ -110,9 +120,8 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
|
||||
internal fun getNestedTypeVariables(type: KotlinType): List<TypeVariable> =
|
||||
type.getNestedTypeParameters().map { getMyTypeVariable(it) }.filterNotNull()
|
||||
|
||||
override fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
|
||||
val newSubjectType = descriptorToVariableSubstitutor.substitute(subjectType, Variance.INVARIANT)
|
||||
addConstraint(SUB_TYPE, newSubjectType, constrainingType, ConstraintContext(constraintPosition, initial = true))
|
||||
override fun addSupertypeConstraint(constrainingType: KotlinType, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
|
||||
addConstraint(SUB_TYPE, subjectType, constrainingType, ConstraintContext(constraintPosition, initial = true))
|
||||
}
|
||||
|
||||
override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
|
||||
@@ -378,7 +387,9 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
|
||||
}
|
||||
|
||||
override fun build(): ConstraintSystem {
|
||||
return ConstraintSystemImpl(allTypeParameterBounds, usedInBounds, errors, initialConstraints, descriptorToVariable)
|
||||
return ConstraintSystemImpl(
|
||||
allTypeParameterBounds, usedInBounds, errors, initialConstraints, descriptorToVariable, typeVariableSubstitutors
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -38,7 +38,8 @@ internal class ConstraintSystemImpl(
|
||||
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
|
||||
private val errors: List<ConstraintError>,
|
||||
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
|
||||
private val descriptorToVariable: Map<TypeParameterDescriptor, TypeVariable>
|
||||
private val descriptorToVariable: Map<TypeParameterDescriptor, TypeVariable>,
|
||||
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
|
||||
) : ConstraintSystem {
|
||||
private val localTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>
|
||||
get() = allTypeParameterBounds.filterNot { it.key.isExternal }
|
||||
@@ -167,6 +168,7 @@ internal class ConstraintSystemImpl(
|
||||
|
||||
result.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) })
|
||||
result.descriptorToVariable.putAll(descriptorToVariable)
|
||||
result.typeVariableSubstitutors.putAll(typeVariableSubstitutors)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
+3
-2
@@ -99,9 +99,10 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() {
|
||||
val context = ConstraintContext(SPECIAL.position(), initial = true)
|
||||
when (constraint.kind) {
|
||||
MyConstraintKind.SUBTYPE -> builder.addSubtypeConstraint(firstType, secondType, context.position)
|
||||
MyConstraintKind.SUPERTYPE -> builder.addSupertypeConstraint(firstType, secondType, context.position)
|
||||
MyConstraintKind.SUPERTYPE -> builder.addSubtypeConstraint(secondType, firstType, context.position)
|
||||
MyConstraintKind.EQUAL -> builder.addConstraint(
|
||||
ConstraintSystemBuilderImpl.ConstraintKind.EQUAL, firstType, secondType, context)
|
||||
ConstraintSystemBuilderImpl.ConstraintKind.EQUAL, firstType, secondType, context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user