diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt index 05dc70c1d82..f8ab00dc801 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/Renderers.kt @@ -251,7 +251,7 @@ public object Renderers { val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(ConstraintPositionKind.TYPE_BOUND_POSITION) val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull { - !ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, it, true) + !ConstraintsUtil.checkUpperBoundIsSatisfied(systemWithoutWeakConstraints, it, inferenceErrorData.call, true) } if (typeParameterDescriptor == null && status.hasConflictingConstraints()) { return renderConflictingSubstitutionsInferenceError(inferenceErrorData, result) @@ -261,8 +261,8 @@ public object Renderers { return result } - val inferredValueForTypeParameter = - systemWithoutWeakConstraints.getTypeBounds(systemWithoutWeakConstraints.descriptorToVariable(typeParameterDescriptor)).value + val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor) + val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value if (inferredValueForTypeParameter == null) { LOG.error(renderDebugMessage("System without weak constraints is not successful, there is no value for type parameter " + typeParameterDescriptor.getName() + "\n: " + systemWithoutWeakConstraints, inferenceErrorData)) 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 34d2db08056..759127392e1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallCompleter.kt @@ -204,7 +204,8 @@ public class CallCompleter( val errorData = InferenceErrorData.create( getCandidateDescriptor(), getConstraintSystem()!!, valueArgumentsCheckingResult.argumentTypes, - receiverType, context.expectedType) + receiverType, context.expectedType, context.call + ) tracing.typeInferenceFailed(context.trace, errorData) addStatus(ResolutionStatus.OTHER_ERROR) 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 7f73d61b1bb..086ce2242c7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/GenericCandidateResolver.kt @@ -32,13 +32,10 @@ import org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext import org.jetbrains.kotlin.resolve.calls.context.ResolutionResultsCache import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem -import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl +import org.jetbrains.kotlin.resolve.calls.inference.* import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION -import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeParameters -import org.jetbrains.kotlin.resolve.calls.inference.getNestedTypeVariables import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TYPE_INFERENCE import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR @@ -56,7 +53,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val candidate = candidateCall.candidateDescriptor val builder = ConstraintSystemBuilderImpl() - builder.registerTypeVariables(candidate.typeParameters) + builder.registerTypeVariables(candidateCall.call.toHandle(), candidate.typeParameters) val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE) @@ -158,7 +155,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap() val freshVariables = returnType.getNestedTypeParameters().map { conversion[it] }.filterNotNull() - builder.registerTypeVariables(freshVariables, external = true) + builder.registerTypeVariables(resultingCall.call.toHandle(), freshVariables, external = true) builder.addSubtypeConstraint(candidateWithFreshVariables.returnType, effectiveExpectedType, constraintPosition) return true 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 d235ae2c4b0..213b7a90eec 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 @@ -34,7 +34,7 @@ interface ConstraintSystem { */ val typeVariables: Set - fun descriptorToVariable(descriptor: TypeParameterDescriptor): TypeVariable + fun descriptorToVariable(call: CallHandle, descriptor: TypeParameterDescriptor): TypeVariable /** * Returns the resulting type constraints of solving the constraint system for specific type parameter descriptor. @@ -66,7 +66,9 @@ interface ConstraintSystem { * Registers variables in a constraint system. Returns a substitutor which maps type parameter descriptors given as parameters * to the corresponding type variables of the system. Use that substitutor to provide constraints to the system */ - fun registerTypeVariables(typeParameters: Collection, external: Boolean = false): TypeSubstitutor + fun registerTypeVariables( + call: CallHandle, typeParameters: Collection, external: Boolean = false + ): TypeSubstitutor /** * Adds a constraint that the constraining type is a subtype 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 dc8d364f63d..88095902759 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 @@ -64,19 +64,25 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder { }) } - override fun registerTypeVariables(typeParameters: Collection, external: Boolean): TypeSubstitutor { + override fun registerTypeVariables( + call: CallHandle, typeParameters: Collection, external: Boolean + ): TypeSubstitutor { if (typeParameters.isEmpty()) return TypeSubstitutor.EMPTY - val typeVariables = (if (external) { - typeParameters.toList() + val typeVariables = if (external) { + typeParameters.map { + TypeVariable(call, it, it, true) + } } - else ArrayList(typeParameters.size).apply { + else { + val freshTypeParameters = ArrayList(typeParameters.size) DescriptorSubstitutor.substituteTypeParameters( - typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, this + typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters ) - }).zip(typeParameters).map { - val (fresh, original) = it - TypeVariable(fresh, original, external) + freshTypeParameters.zip(typeParameters).map { + val (fresh, original) = it + TypeVariable(call, fresh, original, external) + } } for ((descriptor, typeVariable) in typeParameters.zip(typeVariables)) { 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 715d61d4339..19d7ae99f5a 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 @@ -111,8 +111,8 @@ internal class ConstraintSystemImpl( override val typeVariables: Set get() = allTypeParameterBounds.keys - override fun descriptorToVariable(descriptor: TypeParameterDescriptor): TypeVariable = - descriptorToVariable[descriptor] ?: throw IllegalArgumentException("Unknown descriptor: $descriptor") + override fun descriptorToVariable(call: CallHandle, descriptor: TypeParameterDescriptor): TypeVariable = + descriptorToVariable[descriptor] ?: throw IllegalArgumentException("Unknown descriptor: $descriptor, call: $call") override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl { return allTypeParameterBounds[typeVariable] ?: diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java index 14c0c710c6d..039203765c4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/ConstraintsUtil.java @@ -21,6 +21,7 @@ import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor; +import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.types.*; import org.jetbrains.kotlin.types.checker.KotlinTypeChecker; @@ -84,9 +85,11 @@ public class ConstraintsUtil { public static boolean checkUpperBoundIsSatisfied( @NotNull ConstraintSystem constraintSystem, @NotNull TypeParameterDescriptor typeParameter, + @NotNull Call call, boolean substituteOtherTypeParametersInBound ) { - KotlinType type = constraintSystem.getTypeBounds(constraintSystem.descriptorToVariable(typeParameter)).getValue(); + TypeVariable typeVariable = constraintSystem.descriptorToVariable(TypeVariableKt.toHandle(call), typeParameter); + KotlinType type = constraintSystem.getTypeBounds(typeVariable).getValue(); if (type == null) return true; for (KotlinType upperBound : typeParameter.getUpperBounds()) { if (!substituteOtherTypeParametersInBound && diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceErrorData.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceErrorData.java index a286100cb87..806eb18f4b1 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceErrorData.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/InferenceErrorData.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls.inference; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.descriptors.CallableDescriptor; +import org.jetbrains.kotlin.psi.Call; import org.jetbrains.kotlin.types.KotlinType; import java.util.List; @@ -34,22 +35,34 @@ public class InferenceErrorData { public final KotlinType expectedType; @NotNull public final List valueArgumentsTypes; - + @NotNull + public final Call call; private InferenceErrorData( - @NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem, - @NotNull List valueArgumentsTypes, @Nullable KotlinType receiverArgumentType, @NotNull KotlinType expectedType + @NotNull CallableDescriptor descriptor, + @NotNull ConstraintSystem constraintSystem, + @NotNull List valueArgumentsTypes, + @Nullable KotlinType receiverArgumentType, + @NotNull KotlinType expectedType, + @NotNull Call call ) { this.descriptor = descriptor; this.constraintSystem = constraintSystem; this.receiverArgumentType = receiverArgumentType; this.valueArgumentsTypes = valueArgumentsTypes; this.expectedType = expectedType; + this.call = call; } @NotNull - public static InferenceErrorData create(@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem, - @NotNull List valueArgumentsTypes, @Nullable KotlinType receiverArgumentType, @NotNull KotlinType expectedType) { - return new InferenceErrorData(descriptor, constraintSystem, valueArgumentsTypes, receiverArgumentType, expectedType); + public static InferenceErrorData create( + @NotNull CallableDescriptor descriptor, + @NotNull ConstraintSystem constraintSystem, + @NotNull List valueArgumentsTypes, + @Nullable KotlinType receiverArgumentType, + @NotNull KotlinType expectedType, + @NotNull Call call + ) { + return new InferenceErrorData(descriptor, constraintSystem, valueArgumentsTypes, receiverArgumentType, expectedType, call); } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/TypeVariable.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/TypeVariable.kt index c302a0f945f..834115b716d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/TypeVariable.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/TypeVariable.kt @@ -19,13 +19,15 @@ package org.jetbrains.kotlin.resolve.calls.inference import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.Call import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinTypeImpl class TypeVariable( - val freshTypeParameter: TypeParameterDescriptor, + val call: CallHandle, + internal val freshTypeParameter: TypeParameterDescriptor, val originalTypeParameter: TypeParameterDescriptor, val isExternal: Boolean ) { @@ -36,3 +38,20 @@ class TypeVariable( fun hasOnlyInputTypesAnnotation(): Boolean = originalTypeParameter.hasOnlyInputTypesAnnotation() } + +interface CallHandle { + object NONE : CallHandle +} + +class CallBasedCallHandle(val call: Call): CallHandle { + override fun equals(other: Any?) = + other is CallBasedCallHandle && call === other.call + + override fun hashCode() = + System.identityHashCode(call) + + override fun toString() = + call.toString() +} + +fun Call.toHandle(): CallHandle = CallBasedCallHandle(this) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/constraintSystemUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/constraintSystemUtils.kt index 1fedecee99e..f700ed2c925 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/constraintSystemUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/inference/constraintSystemUtils.kt @@ -24,8 +24,10 @@ import org.jetbrains.kotlin.types.TypeProjection import org.jetbrains.kotlin.types.TypeProjectionImpl import java.util.* -fun ConstraintSystem.getNestedTypeVariables(type: KotlinType): List = - type.getNestedTypeParameters().filter { it in typeParameterDescriptors }.map { descriptorToVariable(it) } +fun ConstraintSystem.getNestedTypeVariables(type: KotlinType): List { + val nestedTypeParameters = type.getNestedTypeParameters().toSet() + return typeVariables.filter { it.originalTypeParameter in nestedTypeParameters } +} fun ConstraintSystem.filterConstraintsOut(excludePositionKind: ConstraintPositionKind): ConstraintSystem { return toBuilder { !it.derivedFrom(excludePositionKind) }.build() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java index 3f019bd223f..0ab95bc1d5d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/TypeIntersector.java @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns; 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.inference.CallHandle; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem; import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl; import org.jetbrains.kotlin.resolve.scopes.ChainedScope; @@ -185,7 +186,7 @@ public class TypeIntersector { processAllTypeParameters(withParameters, Variance.INVARIANT, processor); processAllTypeParameters(expected, Variance.INVARIANT, processor); ConstraintSystem.Builder constraintSystem = new ConstraintSystemBuilderImpl(); - constraintSystem.registerTypeVariables(parameters.keySet(), false); + constraintSystem.registerTypeVariables(CallHandle.NONE.INSTANCE, parameters.keySet(), false); constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position()); return constraintSystem.build().getStatus().isSuccessful(); diff --git a/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt b/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt index 248db3025de..9375fd88fc7 100644 --- a/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/resolve/constraintSystem/AbstractConstraintSystemTest.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.diagnostics.rendering.Renderers import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.TypeResolver +import org.jetbrains.kotlin.resolve.calls.inference.CallHandle import org.jetbrains.kotlin.resolve.calls.inference.ConstraintContext import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL @@ -81,7 +82,7 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() { val variables = parseVariables(constraintsFileText) val fixVariables = constraintsFileText.contains("FIX_VARIABLES") val typeParameterDescriptors = variables.map { testDeclarations.getParameterDescriptor(it) } - val substitutor = builder.registerTypeVariables(typeParameterDescriptors) + val substitutor = builder.registerTypeVariables(CallHandle.NONE, typeParameterDescriptors) val constraints = parseConstraints(constraintsFileText) 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 c27afc934cf..784849806a8 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 @@ -20,6 +20,7 @@ package org.jetbrains.kotlin.idea.util import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.resolve.calls.inference.CallHandle import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemBuilderImpl import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind import org.jetbrains.kotlin.types.* @@ -115,7 +116,7 @@ class FuzzyType( } val builder = ConstraintSystemBuilderImpl() - val typeVariableSubstitutor = builder.registerTypeVariables(freeParameters + otherType.freeParameters) + val typeVariableSubstitutor = builder.registerTypeVariables(CallHandle.NONE, freeParameters + otherType.freeParameters) when (matchKind) { MatchKind.IS_SUBTYPE -> builder.addSubtypeConstraint( diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddGenericUpperBoundFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddGenericUpperBoundFix.kt index 7aacb264b6a..c0a370cf8a1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/AddGenericUpperBoundFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/AddGenericUpperBoundFix.kt @@ -87,7 +87,8 @@ public class AddGenericUpperBoundFix( typeParameterDescriptor -> if (ConstraintsUtil.checkUpperBoundIsSatisfied( - successfulConstraintSystem, typeParameterDescriptor, /* substituteOtherTypeParametersInBound */ true + successfulConstraintSystem, typeParameterDescriptor, inferenceData.call, + /* substituteOtherTypeParametersInBound */ true )) return@factory null val upperBound = typeParameterDescriptor.upperBounds.singleOrNull() ?: return@factory null