From cb05a8d58d94bdda5b79d1760ef4077a70f5133f Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 11 Nov 2015 21:10:48 +0300 Subject: [PATCH] Don't use originalToVariableSubstitutor in supertype constraints --- .../resolve/DelegatedPropertyResolver.java | 13 ++++++--- .../kotlin/resolve/calls/CallCompleter.kt | 29 +++++++++++++++---- .../calls/inference/ConstraintSystem.kt | 9 +++++- .../inference/ConstraintSystemBuilderImpl.kt | 25 +++++++++++----- .../calls/inference/ConstraintSystemImpl.kt | 4 ++- .../AbstractConstraintSystemTest.kt | 5 ++-- 6 files changed, 64 insertions(+), 21 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java index fae2ba39e85..b9703775e6d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java @@ -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); } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt index 759127392e1..a1e8356839e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -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 } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt index 213b7a90eec..94ad8138280 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystem.kt @@ -86,7 +86,14 @@ interface ConstraintSystem { * For example, for `fun 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 fun fixVariables() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt index 88095902759..6d66fbc3665 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemBuilderImpl.kt @@ -53,6 +53,8 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { internal val initialConstraints = ArrayList() internal val descriptorToVariable = LinkedHashMap() + override val typeVariableSubstitutors = LinkedHashMap() + 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, 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 = 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 + ) } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt index 19d7ae99f5a..a6408b8d3a0 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintSystemImpl.kt @@ -38,7 +38,8 @@ internal class ConstraintSystemImpl( private val usedInBounds: Map>, private val errors: List, private val initialConstraints: List, - private val descriptorToVariable: Map + private val descriptorToVariable: Map, + private val typeVariableSubstitutors: Map ) : ConstraintSystem { private val localTypeParameterBounds: Map 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 } diff --git a/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt b/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt index 9375fd88fc7..a41a04aa254 100644 --- a/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt @@ -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 + ) } }