Don't use originalToVariableSubstitutor in supertype constraints

This commit is contained in:
Alexander Udalov
2015-11-11 21:10:48 +03:00
parent 178ca3daae
commit cb05a8d58d
6 changed files with 64 additions and 21 deletions
@@ -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
}
}
@@ -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()
@@ -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
)
}
}
@@ -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
}
@@ -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
)
}
}