From d4664af4e5cbe5dfdf3dbdd507fa3c3ccca1b4ed Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 11 Nov 2015 21:29:44 +0300 Subject: [PATCH] Get rid of originalToVariableSubstitutor and descriptorToVariable Move the composite substitutor to GenericCandidateResolver where it was used, other places don't need it since they know the exact call (or NO_CALL), the substitutor for which should be used --- .../resolve/DelegatedPropertyResolver.java | 30 +++++++++---- .../resolve/calls/GenericCandidateResolver.kt | 43 ++++++++++++++++--- .../calls/inference/ConstraintSystem.kt | 2 +- .../inference/ConstraintSystemBuilderImpl.kt | 22 ++-------- .../calls/inference/ConstraintSystemImpl.kt | 8 ++-- .../kotlin/types/TypeIntersector.java | 4 +- .../jetbrains/kotlin/idea/util/FuzzyType.kt | 17 +++----- 7 files changed, 74 insertions(+), 52 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java index b9703775e6d..5af3b6e7abf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/DelegatedPropertyResolver.java @@ -356,6 +356,10 @@ public class DelegatedPropertyResolver { KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType(); if (returnType == null) return; + TypeSubstitutor typeVariableSubstitutor = + constraintSystem.getTypeVariableSubstitutors().get(TypeVariableKt.toHandle(resolvedCall.getCall())); + assert typeVariableSubstitutor != null : "No substitutor in the system for call: " + resolvedCall.getCall(); + TemporaryBindingTrace traceToResolveConventionMethods = TemporaryBindingTrace.create(trace, "Trace to resolve delegated property convention methods"); OverloadResolutionResults @@ -368,15 +372,12 @@ public class DelegatedPropertyResolver { FunctionDescriptor descriptor = getMethodResults.getResultingDescriptor(); KotlinType returnTypeOfGetMethod = descriptor.getReturnType(); if (returnTypeOfGetMethod != null && !TypeUtils.noExpectedType(expectedType)) { - 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); + KotlinType returnTypeInSystem = typeVariableSubstitutor.substitute(returnTypeOfGetMethod, Variance.INVARIANT); if (returnTypeInSystem != null) { constraintSystem.addSupertypeConstraint(expectedType, returnTypeInSystem, FROM_COMPLETER.position()); } } - addConstraintForThisValue(constraintSystem, descriptor); + addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor); } if (!propertyDescriptor.isVar()) return; @@ -399,9 +400,12 @@ public class DelegatedPropertyResolver { if (!noExpectedType(expectedType)) { constraintSystem.addSubtypeConstraint( - expectedType, valueParameterForThis.getType(), FROM_COMPLETER.position()); + expectedType, + typeVariableSubstitutor.substitute(valueParameterForThis.getType(), Variance.INVARIANT), + FROM_COMPLETER.position() + ); } - addConstraintForThisValue(constraintSystem, descriptor); + addConstraintForThisValue(constraintSystem, typeVariableSubstitutor, descriptor); } } } @@ -412,7 +416,11 @@ public class DelegatedPropertyResolver { results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH); } - private void addConstraintForThisValue(ConstraintSystem.Builder constraintSystem, FunctionDescriptor resultingDescriptor) { + private void addConstraintForThisValue( + ConstraintSystem.Builder constraintSystem, + TypeSubstitutor typeVariableSubstitutor, + FunctionDescriptor resultingDescriptor + ) { ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter(); ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter(); KotlinType typeOfThis = @@ -424,7 +432,11 @@ public class DelegatedPropertyResolver { if (valueParameters.isEmpty()) return; ValueParameterDescriptor valueParameterForThis = valueParameters.get(0); - constraintSystem.addSubtypeConstraint(typeOfThis, valueParameterForThis.getType(), FROM_COMPLETER.position()); + constraintSystem.addSubtypeConstraint( + typeOfThis, + typeVariableSubstitutor.substitute(valueParameterForThis.getType(), Variance.INVARIANT), + FROM_COMPLETER.position() + ); } }; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt index 086ce2242c7..bb89d973ae7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -86,7 +86,11 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes if (receiverArgument is ExpressionReceiver) { receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context) } - builder.addSubtypeConstraint(receiverType, receiverParameter.type, RECEIVER_POSITION.position()) + builder.addSubtypeConstraint( + receiverType, + builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT), + RECEIVER_POSITION.position() + ) } val constraintSystem = builder.build() @@ -100,6 +104,16 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes return OTHER_ERROR } + // Creates a substitutor which maps types to their representation in the constraint system. + // In case when some type parameter descriptor is represented by more than one variable in the system, the behavior is undefined. + private fun ConstraintSystem.Builder.compositeSubstitutor(): TypeSubstitutor { + return TypeSubstitutor.create(object : TypeSubstitution() { + override fun get(key: KotlinType): TypeProjection? { + return typeVariableSubstitutors.values.reversed().asSequence().mapNotNull { it.substitution.get(key) }.firstOrNull() + } + }) + } + fun addConstraintForValueArgument( valueArgument: ValueArgument, valueParameterDescriptor: ValueParameterDescriptor, @@ -108,7 +122,6 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes context: CallCandidateResolutionContext<*>, resolveFunctionArgumentBodies: ResolveArgumentsMode ) { - val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument) val argumentExpression = valueArgument.getArgumentExpression() @@ -124,7 +137,11 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument)) - builder.addSubtypeConstraint(type, effectiveExpectedType, constraintPosition) + builder.addSubtypeConstraint( + type, + builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT), + constraintPosition + ) } private fun addConstraintForNestedCall( @@ -157,7 +174,12 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val freshVariables = returnType.getNestedTypeParameters().map { conversion[it] }.filterNotNull() builder.registerTypeVariables(resultingCall.call.toHandle(), freshVariables, external = true) - builder.addSubtypeConstraint(candidateWithFreshVariables.returnType, effectiveExpectedType, constraintPosition) + builder.addSubtypeConstraint( + candidateWithFreshVariables.returnType, + builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT), + constraintPosition + ) + return true } @@ -222,6 +244,9 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val dataFlowInfoForArguments = context.candidateCall.dataFlowInfoForArguments val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument) + val effectiveExpectedTypeInSystem = + constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT) + //todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type val hasExpectedReturnType = !hasUnknownReturnType(expectedType) val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) @@ -239,7 +264,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val type = argumentTypeResolver.getFunctionLiteralTypeInfo( argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type if (!mismatch[0]) { - constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, position) + constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position) temporaryToResolveFunctionLiteral.commit() return } @@ -248,7 +273,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val newContext = context.replaceExpectedType(expectedTypeWithoutReturnType).replaceDataFlowInfo(dataFlowInfoForArgument) .replaceContextDependency(INDEPENDENT) val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type - constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, position) + constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position) } private fun addConstraintForCallableReference( @@ -264,7 +289,11 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes if (!ReflectionTypes.isCallableType(expectedType)) return val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index) - constraintSystem.addSubtypeConstraint(resolvedType, effectiveExpectedType, position) + constraintSystem.addSubtypeConstraint( + resolvedType, + constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT), + position + ) } private fun getExpectedTypeForCallableReference( 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 94ad8138280..0e82d7b21cf 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 @@ -77,7 +77,7 @@ interface ConstraintSystem { * For example, for `fun id(t: T) {}` to infer `T` in invocation `id(1)` * the constraint "Int is a subtype of T" should be generated where T is a subject type, and Int is a constraining type. */ - fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) + fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType?, constraintPosition: ConstraintPosition) /** * Adds a constraint that the constraining type is a supertype of the subject type. 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 6d66fbc3665..3b2f2cc95f8 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 @@ -51,21 +51,9 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { internal val usedInBounds = HashMap>() internal val errors = ArrayList() 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? { - val descriptor = key.declarationDescriptor - if (descriptor !is TypeParameterDescriptor) return null - val typeVariable = descriptorToVariable[descriptor] ?: return null - return TypeProjectionImpl(typeVariable.type) - } - }) - } - 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") @@ -97,7 +85,6 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { for ((descriptor, typeVariable) in typeParameters.zip(typeVariables)) { allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable)) - descriptorToVariable[descriptor] = typeVariable } for ((typeVariable, typeBounds) in allTypeParameterBounds) { @@ -124,9 +111,8 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { addConstraint(SUB_TYPE, subjectType, constrainingType, ConstraintContext(constraintPosition, initial = true)) } - override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) { - val newSubjectType = descriptorToVariableSubstitutor.substitute(subjectType, Variance.INVARIANT) - addConstraint(SUB_TYPE, constrainingType, newSubjectType, ConstraintContext(constraintPosition, initial = true)) + override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType?, constraintPosition: ConstraintPosition) { + addConstraint(SUB_TYPE, constrainingType, subjectType, ConstraintContext(constraintPosition, initial = true)) } fun addConstraint( @@ -387,9 +373,7 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { } override fun build(): ConstraintSystem { - return ConstraintSystemImpl( - allTypeParameterBounds, usedInBounds, errors, initialConstraints, descriptorToVariable, typeVariableSubstitutors - ) + return ConstraintSystemImpl(allTypeParameterBounds, usedInBounds, errors, initialConstraints, 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 a6408b8d3a0..a1dcba7d88a 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,6 @@ internal class ConstraintSystemImpl( private val usedInBounds: Map>, private val errors: List, private val initialConstraints: List, - private val descriptorToVariable: Map, private val typeVariableSubstitutors: Map ) : ConstraintSystem { private val localTypeParameterBounds: Map @@ -107,13 +106,15 @@ internal class ConstraintSystemImpl( } override val typeParameterDescriptors: Set - get() = descriptorToVariable.keys + get() = typeVariables.map { it.originalTypeParameter }.toSet() override val typeVariables: Set get() = allTypeParameterBounds.keys override fun descriptorToVariable(call: CallHandle, descriptor: TypeParameterDescriptor): TypeVariable = - descriptorToVariable[descriptor] ?: throw IllegalArgumentException("Unknown descriptor: $descriptor, call: $call") + typeVariables.firstOrNull { + it.call == call && it.originalTypeParameter == descriptor + } ?: throw IllegalArgumentException("Unknown descriptor: $descriptor, call: $call") override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl { return allTypeParameterBounds[typeVariable] ?: @@ -167,7 +168,6 @@ internal class ConstraintSystemImpl( result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) }) result.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) }) - result.descriptorToVariable.putAll(descriptorToVariable) result.typeVariableSubstitutors.putAll(typeVariableSubstitutors) return result diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java index 0ab95bc1d5d..555be20c322 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java @@ -186,8 +186,8 @@ public class TypeIntersector { processAllTypeParameters(withParameters, Variance.INVARIANT, processor); processAllTypeParameters(expected, Variance.INVARIANT, processor); ConstraintSystem.Builder constraintSystem = new ConstraintSystemBuilderImpl(); - constraintSystem.registerTypeVariables(CallHandle.NONE.INSTANCE, parameters.keySet(), false); - constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position()); + TypeSubstitutor substitutor = constraintSystem.registerTypeVariables(CallHandle.NONE.INSTANCE, parameters.keySet(), false); + constraintSystem.addSubtypeConstraint(withParameters, substitutor.substitute(expected, Variance.INVARIANT), SPECIAL.position()); return constraintSystem.build().getStatus().isSuccessful(); } diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt index 784849806a8..1d3964e75c7 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/FuzzyType.kt @@ -118,17 +118,14 @@ class FuzzyType( val builder = ConstraintSystemBuilderImpl() val typeVariableSubstitutor = builder.registerTypeVariables(CallHandle.NONE, freeParameters + otherType.freeParameters) + val typeInSystem = typeVariableSubstitutor.substitute(type, Variance.INVARIANT) + val otherTypeInSystem = typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT) + when (matchKind) { - MatchKind.IS_SUBTYPE -> builder.addSubtypeConstraint( - typeVariableSubstitutor.substitute(type, Variance.INVARIANT), - otherType.type, - ConstraintPositionKind.RECEIVER_POSITION.position() - ) - MatchKind.IS_SUPERTYPE -> builder.addSubtypeConstraint( - typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT), - type, - ConstraintPositionKind.RECEIVER_POSITION.position() - ) + MatchKind.IS_SUBTYPE -> + builder.addSubtypeConstraint(typeInSystem, otherTypeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position()) + MatchKind.IS_SUPERTYPE -> + builder.addSubtypeConstraint(otherTypeInSystem, typeInSystem, ConstraintPositionKind.RECEIVER_POSITION.position()) } builder.fixVariables()