Add call to type variable and mapping descriptor -> variable
Since type parameter descriptor represents a single declaration of a type parameter, multiple variables in one system may correspond to one type parameter (e.g. in case of nested calls). Hence it's not possible to map type parameters uniquely onto type variables and additional information is required
This commit is contained in:
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
+3
-6
@@ -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
|
||||
|
||||
+4
-2
@@ -34,7 +34,7 @@ interface ConstraintSystem {
|
||||
*/
|
||||
val typeVariables: Set<TypeVariable>
|
||||
|
||||
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<TypeParameterDescriptor>, external: Boolean = false): TypeSubstitutor
|
||||
fun registerTypeVariables(
|
||||
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean = false
|
||||
): TypeSubstitutor
|
||||
|
||||
/**
|
||||
* Adds a constraint that the constraining type is a subtype of the subject type.
|
||||
|
||||
+14
-8
@@ -64,19 +64,25 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
|
||||
})
|
||||
}
|
||||
|
||||
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>, external: Boolean): TypeSubstitutor {
|
||||
override fun registerTypeVariables(
|
||||
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, 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<TypeParameterDescriptor>(typeParameters.size).apply {
|
||||
else {
|
||||
val freshTypeParameters = ArrayList<TypeParameterDescriptor>(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)) {
|
||||
|
||||
+2
-2
@@ -111,8 +111,8 @@ internal class ConstraintSystemImpl(
|
||||
override val typeVariables: Set<TypeVariable>
|
||||
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] ?:
|
||||
|
||||
+4
-1
@@ -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 &&
|
||||
|
||||
+19
-6
@@ -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<KotlinType> valueArgumentsTypes;
|
||||
|
||||
@NotNull
|
||||
public final Call call;
|
||||
|
||||
private InferenceErrorData(
|
||||
@NotNull CallableDescriptor descriptor, @NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull List<KotlinType> valueArgumentsTypes, @Nullable KotlinType receiverArgumentType, @NotNull KotlinType expectedType
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@NotNull ConstraintSystem constraintSystem,
|
||||
@NotNull List<KotlinType> 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<KotlinType> 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<KotlinType> valueArgumentsTypes,
|
||||
@Nullable KotlinType receiverArgumentType,
|
||||
@NotNull KotlinType expectedType,
|
||||
@NotNull Call call
|
||||
) {
|
||||
return new InferenceErrorData(descriptor, constraintSystem, valueArgumentsTypes, receiverArgumentType, expectedType, call);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
+4
-2
@@ -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<TypeVariable> =
|
||||
type.getNestedTypeParameters().filter { it in typeParameterDescriptors }.map { descriptorToVariable(it) }
|
||||
fun ConstraintSystem.getNestedTypeVariables(type: KotlinType): List<TypeVariable> {
|
||||
val nestedTypeParameters = type.getNestedTypeParameters().toSet()
|
||||
return typeVariables.filter { it.originalTypeParameter in nestedTypeParameters }
|
||||
}
|
||||
|
||||
fun ConstraintSystem.filterConstraintsOut(excludePositionKind: ConstraintPositionKind): ConstraintSystem {
|
||||
return toBuilder { !it.derivedFrom(excludePositionKind) }.build()
|
||||
|
||||
@@ -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();
|
||||
|
||||
+2
-1
@@ -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)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user