Move mutating methods of ConstraintSystem to Builder
Extract immutable ConstraintSystemSnapshot from ConstraintSystemImpl
This commit is contained in:
@@ -352,7 +352,7 @@ public class DelegatedPropertyResolver {
|
|||||||
return new ConstraintSystemCompleter() {
|
return new ConstraintSystemCompleter() {
|
||||||
@Override
|
@Override
|
||||||
public void completeConstraintSystem(
|
public void completeConstraintSystem(
|
||||||
@NotNull ConstraintSystem constraintSystem, @NotNull ResolvedCall<?> resolvedCall
|
@NotNull ConstraintSystem.Builder constraintSystem, @NotNull ResolvedCall<?> resolvedCall
|
||||||
) {
|
) {
|
||||||
KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
|
KotlinType returnType = resolvedCall.getCandidateDescriptor().getReturnType();
|
||||||
if (returnType == null) return;
|
if (returnType == null) return;
|
||||||
@@ -407,7 +407,7 @@ public class DelegatedPropertyResolver {
|
|||||||
results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
|
results.getResultCode() == OverloadResolutionResults.Code.SINGLE_CANDIDATE_ARGUMENT_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addConstraintForThisValue(ConstraintSystem constraintSystem, FunctionDescriptor resultingDescriptor) {
|
private void addConstraintForThisValue(ConstraintSystem.Builder constraintSystem, FunctionDescriptor resultingDescriptor) {
|
||||||
ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter();
|
ReceiverParameterDescriptor extensionReceiver = propertyDescriptor.getExtensionReceiverParameter();
|
||||||
ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter();
|
ReceiverParameterDescriptor dispatchReceiver = propertyDescriptor.getDispatchReceiverParameter();
|
||||||
KotlinType typeOfThis =
|
KotlinType typeOfThis =
|
||||||
|
|||||||
@@ -139,16 +139,19 @@ public class CallCompleter(
|
|||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
fun updateSystemIfSuccessful(update: (ConstraintSystem) -> Boolean) {
|
fun updateSystemIfNeeded(buildSystemWithAdditionalConstraints: (ConstraintSystem.Builder) -> ConstraintSystem?) {
|
||||||
val copy = constraintSystem!!.copy()
|
val system = buildSystemWithAdditionalConstraints(constraintSystem!!.toBuilder())
|
||||||
if (update(copy)) {
|
if (system != null) {
|
||||||
setConstraintSystem(copy)
|
setConstraintSystem(system)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val returnType = getCandidateDescriptor().getReturnType()
|
val returnType = getCandidateDescriptor().getReturnType()
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
constraintSystem!!.addSupertypeConstraint(expectedType, returnType, EXPECTED_TYPE_POSITION.position())
|
updateSystemIfNeeded { builder ->
|
||||||
|
builder.addSupertypeConstraint(expectedType, returnType, EXPECTED_TYPE_POSITION.position())
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val constraintSystemCompleter = trace[CONSTRAINT_SYSTEM_COMPLETER, getCall().getCalleeExpression()]
|
val constraintSystemCompleter = trace[CONSTRAINT_SYSTEM_COMPLETER, getCall().getCalleeExpression()]
|
||||||
@@ -156,24 +159,29 @@ public class CallCompleter(
|
|||||||
// todo improve error reporting with errors in constraints from completer
|
// todo improve error reporting with errors in constraints from completer
|
||||||
// todo add constraints from completer unconditionally; improve constraints from completer for generic methods
|
// todo add constraints from completer unconditionally; improve constraints from completer for generic methods
|
||||||
// add the constraints only if they don't lead to errors (except errors from upper bounds to improve diagnostics)
|
// add the constraints only if they don't lead to errors (except errors from upper bounds to improve diagnostics)
|
||||||
updateSystemIfSuccessful {
|
updateSystemIfNeeded { builder ->
|
||||||
system ->
|
constraintSystemCompleter.completeConstraintSystem(builder, this)
|
||||||
constraintSystemCompleter.completeConstraintSystem(system, this)
|
val system = builder.build()
|
||||||
!system.filterConstraintsOut(TYPE_BOUND_POSITION).getStatus().hasOnlyErrorsDerivedFrom(FROM_COMPLETER)
|
val status = system.filterConstraintsOut(TYPE_BOUND_POSITION).getStatus()
|
||||||
|
if (status.hasOnlyErrorsDerivedFrom(FROM_COMPLETER)) null else system
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (returnType != null && expectedType === TypeUtils.UNIT_EXPECTED_TYPE) {
|
if (returnType != null && expectedType === TypeUtils.UNIT_EXPECTED_TYPE) {
|
||||||
updateSystemIfSuccessful {
|
updateSystemIfNeeded { builder ->
|
||||||
system ->
|
builder.addSupertypeConstraint(builtIns.getUnitType(), returnType, EXPECTED_TYPE_POSITION.position())
|
||||||
system.addSupertypeConstraint(builtIns.getUnitType(), returnType, EXPECTED_TYPE_POSITION.position())
|
val system = builder.build()
|
||||||
system.getStatus().isSuccessful()
|
if (system.getStatus().isSuccessful()) system else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constraintSystem!!.fixVariables()
|
|
||||||
|
|
||||||
setResultingSubstitutor(constraintSystem!!.getResultingSubstitutor())
|
val builder = constraintSystem!!.toBuilder()
|
||||||
|
builder.fixVariables()
|
||||||
|
val system = builder.build()
|
||||||
|
setConstraintSystem(system)
|
||||||
|
|
||||||
|
setResultingSubstitutor(system.getResultingSubstitutor())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ private fun getReturnTypeForCallable(type: KotlinType) =
|
|||||||
|
|
||||||
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
||||||
val returnType = returnType ?: return false
|
val returnType = returnType ?: return false
|
||||||
val nestedTypeVariables = constraintSystem.getNestedTypeVariables(returnType, original = true)
|
val nestedTypeVariables = constraintSystem.getNestedTypeVariables(returnType)
|
||||||
return nestedTypeVariables.any { constraintSystem.getTypeBounds(it).value == null }
|
return nestedTypeVariables.any { constraintSystem.getTypeBounds(it).value == null }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+25
-20
@@ -53,8 +53,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
val candidateCall = context.candidateCall
|
val candidateCall = context.candidateCall
|
||||||
val candidate = candidateCall.candidateDescriptor
|
val candidate = candidateCall.candidateDescriptor
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
val builder = ConstraintSystemImpl()
|
||||||
candidateCall.setConstraintSystem(constraintSystem)
|
|
||||||
|
|
||||||
// If the call is recursive, e.g.
|
// If the call is recursive, e.g.
|
||||||
// fun foo<T>(t : T) : T = foo(t)
|
// fun foo<T>(t : T) : T = foo(t)
|
||||||
@@ -65,7 +64,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
||||||
|
|
||||||
val conversionToOriginal = candidateWithFreshVariables.typeParameters.zip(candidate.typeParameters).toMap()
|
val conversionToOriginal = candidateWithFreshVariables.typeParameters.zip(candidate.typeParameters).toMap()
|
||||||
constraintSystem.registerTypeVariables(candidateWithFreshVariables.typeParameters, { conversionToOriginal[it]!! })
|
builder.registerTypeVariables(candidateWithFreshVariables.typeParameters, { conversionToOriginal[it]!! })
|
||||||
|
|
||||||
val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE)
|
val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE)
|
||||||
|
|
||||||
@@ -79,8 +78,9 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
// Here we type check expecting an error type (DONT_CARE, substitution with substituteDontCare)
|
||||||
// and throw the results away
|
// and throw the results away
|
||||||
// We'll type check the arguments later, with the inferred types expected
|
// We'll type check the arguments later, with the inferred types expected
|
||||||
addConstraintForValueArgument(valueArgument, valueParameterDescriptor, substituteDontCare,
|
addConstraintForValueArgument(
|
||||||
constraintSystem, context, SHAPE_FUNCTION_ARGUMENTS)
|
valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,9 +97,12 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
if (receiverArgument is ExpressionReceiver) {
|
if (receiverArgument is ExpressionReceiver) {
|
||||||
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
||||||
}
|
}
|
||||||
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.type, RECEIVER_POSITION.position())
|
builder.addSubtypeConstraint(receiverType, receiverParameter.type, RECEIVER_POSITION.position())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val constraintSystem = builder.build()
|
||||||
|
candidateCall.setConstraintSystem(constraintSystem)
|
||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
val hasContradiction = constraintSystem.getStatus().hasContradiction()
|
val hasContradiction = constraintSystem.getStatus().hasContradiction()
|
||||||
if (!hasContradiction) {
|
if (!hasContradiction) {
|
||||||
@@ -112,7 +115,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
valueParameterDescriptor: ValueParameterDescriptor,
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
substitutor: TypeSubstitutor,
|
substitutor: TypeSubstitutor,
|
||||||
constraintSystem: ConstraintSystem,
|
builder: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||||
) {
|
) {
|
||||||
@@ -129,16 +132,16 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
|
|
||||||
val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
val constraintPosition = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||||
|
|
||||||
if (addConstraintForNestedCall(argumentExpression, constraintPosition, constraintSystem, newContext, effectiveExpectedType)) return
|
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return
|
||||||
|
|
||||||
val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
|
val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
|
||||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedType, constraintPosition)
|
builder.addSubtypeConstraint(type, effectiveExpectedType, constraintPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addConstraintForNestedCall(
|
private fun addConstraintForNestedCall(
|
||||||
argumentExpression: KtExpression?,
|
argumentExpression: KtExpression?,
|
||||||
constraintPosition: ConstraintPosition,
|
constraintPosition: ConstraintPosition,
|
||||||
constraintSystem: ConstraintSystem,
|
builder: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
effectiveExpectedType: KotlinType
|
effectiveExpectedType: KotlinType
|
||||||
): Boolean {
|
): Boolean {
|
||||||
@@ -153,7 +156,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
val candidateDescriptor = resultingCall.candidateDescriptor
|
val candidateDescriptor = resultingCall.candidateDescriptor
|
||||||
val returnType = candidateDescriptor.returnType ?: return false
|
val returnType = candidateDescriptor.returnType ?: return false
|
||||||
|
|
||||||
val nestedTypeVariables = argumentConstraintSystem.getNestedTypeVariables(returnType, original = true)
|
val nestedTypeVariables = argumentConstraintSystem.getNestedTypeVariables(returnType)
|
||||||
|
|
||||||
// we add an additional type variable only if no information is inferred for it.
|
// we add an additional type variable only if no information is inferred for it.
|
||||||
// otherwise we add currently inferred return type as before
|
// otherwise we add currently inferred return type as before
|
||||||
@@ -163,9 +166,9 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap()
|
val conversion = candidateDescriptor.typeParameters.zip(candidateWithFreshVariables.typeParameters).toMap()
|
||||||
|
|
||||||
val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull()
|
val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull()
|
||||||
constraintSystem.registerTypeVariables(freshVariables, external = true)
|
builder.registerTypeVariables(freshVariables, external = true)
|
||||||
|
|
||||||
constraintSystem.addSubtypeConstraint(candidateWithFreshVariables.returnType, effectiveExpectedType, constraintPosition)
|
builder.addSubtypeConstraint(candidateWithFreshVariables.returnType, effectiveExpectedType, constraintPosition)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +191,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
|
|
||||||
fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext<D>) {
|
fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(context: CallCandidateResolutionContext<D>) {
|
||||||
val resolvedCall = context.candidateCall
|
val resolvedCall = context.candidateCall
|
||||||
val constraintSystem = resolvedCall.constraintSystem ?: return
|
val constraintSystem = resolvedCall.constraintSystem?.toBuilder() ?: return
|
||||||
|
|
||||||
// constraints for function literals
|
// constraints for function literals
|
||||||
// Value parameters
|
// Value parameters
|
||||||
@@ -204,20 +207,22 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolvedCall.setResultingSubstitutor(constraintSystem.getResultingSubstitutor())
|
val resultingSystem = constraintSystem.build()
|
||||||
|
resolvedCall.setConstraintSystem(resultingSystem)
|
||||||
|
resolvedCall.setResultingSubstitutor(resultingSystem.getResultingSubstitutor())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> addConstraintForFunctionLiteral(
|
private fun <D : CallableDescriptor> addConstraintForFunctionLiteral(
|
||||||
functionLiteral: KtFunction,
|
functionLiteral: KtFunction,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
valueParameterDescriptor: ValueParameterDescriptor,
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
constraintSystem: ConstraintSystem,
|
constraintSystem: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<D>
|
context: CallCandidateResolutionContext<D>
|
||||||
) {
|
) {
|
||||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||||
|
|
||||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
|
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
|
||||||
var expectedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
|
var expectedType = constraintSystem.build().getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||||
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
|
if (expectedType == null || TypeUtils.isDontCarePlaceholder(expectedType)) {
|
||||||
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false)
|
expectedType = argumentTypeResolver.getShapeTypeOfFunctionLiteral(functionLiteral, context.scope, context.trace, false)
|
||||||
}
|
}
|
||||||
@@ -261,7 +266,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
callableReference: KtCallableReferenceExpression,
|
callableReference: KtCallableReferenceExpression,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
valueParameterDescriptor: ValueParameterDescriptor,
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
constraintSystem: ConstraintSystem,
|
constraintSystem: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<D>
|
context: CallCandidateResolutionContext<D>
|
||||||
) {
|
) {
|
||||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
|
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument)
|
||||||
@@ -275,11 +280,11 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
|
|||||||
|
|
||||||
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
|
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
|
||||||
callableReference: KtCallableReferenceExpression,
|
callableReference: KtCallableReferenceExpression,
|
||||||
constraintSystem: ConstraintSystem,
|
constraintSystem: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
effectiveExpectedType: KotlinType
|
effectiveExpectedType: KotlinType
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val substitutedType = constraintSystem.getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
|
val substitutedType = constraintSystem.build().getCurrentSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||||
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
|
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
|
||||||
return substitutedType
|
return substitutedType
|
||||||
|
|
||||||
|
|||||||
+43
-39
@@ -23,47 +23,19 @@ import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.derivedFr
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
|
|
||||||
public interface ConstraintSystem {
|
interface ConstraintSystem {
|
||||||
/**
|
|
||||||
* Registers variables in a constraint system.
|
|
||||||
* The type variables for the corresponding function are local, the type variables of inner arguments calls are non-local.
|
|
||||||
*/
|
|
||||||
public fun registerTypeVariables(
|
|
||||||
typeVariables: Collection<TypeParameterDescriptor>,
|
|
||||||
mapToOriginal: (TypeParameterDescriptor) -> TypeParameterDescriptor = { it },
|
|
||||||
external: Boolean = false
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a set of all non-external registered type variables.
|
* Returns a set of all non-external registered type variables.
|
||||||
*/
|
*/
|
||||||
public fun getTypeVariables(): Set<TypeParameterDescriptor>
|
fun getTypeVariables(): Set<TypeParameterDescriptor>
|
||||||
|
|
||||||
/**
|
fun getStatus(): ConstraintSystemStatus
|
||||||
* Adds a constraint that the constraining type is a subtype of the subject type.
|
|
||||||
* Asserts that only subject type may contain registered type variables.
|
|
||||||
*
|
|
||||||
* For example, for `fun <T> 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.
|
|
||||||
*/
|
|
||||||
public fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a constraint that the constraining type is a supertype of the subject type.
|
|
||||||
* Asserts that only subject type may contain registered type variables.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
public fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition)
|
|
||||||
|
|
||||||
public fun getStatus(): ConstraintSystemStatus
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the resulting type constraints of solving the constraint system for specific type variable.
|
* Returns the resulting type constraints of solving the constraint system for specific type variable.
|
||||||
* Throws IllegalArgumentException if the type variable was not registered.
|
* Throws IllegalArgumentException if the type variable was not registered.
|
||||||
*/
|
*/
|
||||||
public fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds
|
fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBounds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the result of solving the constraint system (mapping from the type variable to the resulting type projection).
|
* Returns the result of solving the constraint system (mapping from the type variable to the resulting type projection).
|
||||||
@@ -74,26 +46,58 @@ public interface ConstraintSystem {
|
|||||||
* If the addition of the 'expected type' constraint made the system fail,
|
* If the addition of the 'expected type' constraint made the system fail,
|
||||||
* this constraint is not included in the resulting substitution.
|
* this constraint is not included in the resulting substitution.
|
||||||
*/
|
*/
|
||||||
public fun getResultingSubstitutor(): TypeSubstitutor
|
fun getResultingSubstitutor(): TypeSubstitutor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current result of solving the constraint system (mapping from the type variable to the resulting type projection).
|
* Returns the current result of solving the constraint system (mapping from the type variable to the resulting type projection).
|
||||||
* If there is no information for type parameter, returns type projection for DONT_CARE type.
|
* If there is no information for type parameter, returns type projection for DONT_CARE type.
|
||||||
*/
|
*/
|
||||||
public fun getCurrentSubstitutor(): TypeSubstitutor
|
fun getCurrentSubstitutor(): TypeSubstitutor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the substitution only for type parameters that have result values, otherwise returns the type parameter itself.
|
* Returns the substitution only for type parameters that have result values, otherwise returns the type parameter itself.
|
||||||
*/
|
*/
|
||||||
public fun getPartialSubstitutor(): TypeSubstitutor
|
fun getPartialSubstitutor(): TypeSubstitutor
|
||||||
|
|
||||||
public fun copy(filterConstraintPosition: (ConstraintPosition) -> Boolean = { true }): ConstraintSystem
|
fun getNestedTypeVariables(type: KotlinType): List<TypeParameterDescriptor>
|
||||||
|
|
||||||
public fun fixVariables()
|
fun toBuilder(filterConstraintPosition: (ConstraintPosition) -> Boolean = { true }): Builder
|
||||||
|
|
||||||
public fun getNestedTypeVariables(type: KotlinType, original: Boolean): List<TypeParameterDescriptor>
|
interface Builder {
|
||||||
|
/**
|
||||||
|
* Registers variables in a constraint system.
|
||||||
|
* The type variables for the corresponding function are local, the type variables of inner arguments calls are non-local.
|
||||||
|
*/
|
||||||
|
fun registerTypeVariables(
|
||||||
|
typeVariables: Collection<TypeParameterDescriptor>,
|
||||||
|
mapToOriginal: (TypeParameterDescriptor) -> TypeParameterDescriptor = { it },
|
||||||
|
external: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a constraint that the constraining type is a subtype of the subject type.
|
||||||
|
* Asserts that only subject type may contain registered type variables.
|
||||||
|
*
|
||||||
|
* For example, for `fun <T> 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)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a constraint that the constraining type is a supertype of the subject type.
|
||||||
|
* Asserts that only subject type may contain registered type variables.
|
||||||
|
*
|
||||||
|
* 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 fixVariables()
|
||||||
|
|
||||||
|
fun build(): ConstraintSystem
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ConstraintSystem.filterConstraintsOut(excludePositionKind: ConstraintPositionKind): ConstraintSystem {
|
fun ConstraintSystem.filterConstraintsOut(excludePositionKind: ConstraintPositionKind): ConstraintSystem {
|
||||||
return copy { !it.derivedFrom(excludePositionKind) }
|
return toBuilder { !it.derivedFrom(excludePositionKind) }.build()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
|||||||
|
|
||||||
public interface ConstraintSystemCompleter {
|
public interface ConstraintSystemCompleter {
|
||||||
void completeConstraintSystem(
|
void completeConstraintSystem(
|
||||||
@NotNull ConstraintSystem constraintSystem,
|
@NotNull ConstraintSystem.Builder constraintSystem,
|
||||||
@NotNull ResolvedCall<?> resolvedCall
|
@NotNull ResolvedCall<?> resolvedCall
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-144
@@ -27,21 +27,21 @@ import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.*
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.TYPE_BOUND_POSITION
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.TYPE_BOUND_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.derivedFrom
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasExactAnnotation
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.*
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasInternalAnnotationForResolve
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasNoInferAnnotation
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isInternalAnnotationForResolve
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
|
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedure
|
||||||
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
|
import org.jetbrains.kotlin.types.checker.TypeCheckingProcedureCallbacks
|
||||||
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
import org.jetbrains.kotlin.types.typeUtil.builtIns
|
||||||
import org.jetbrains.kotlin.types.typeUtil.getNestedArguments
|
import org.jetbrains.kotlin.types.typeUtil.getNestedArguments
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isDefaultBound
|
import org.jetbrains.kotlin.types.typeUtil.isDefaultBound
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
public class ConstraintSystemImpl : ConstraintSystem {
|
public class ConstraintSystemImpl : ConstraintSystem.Builder {
|
||||||
|
|
||||||
data class Constraint(val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition)
|
data class Constraint(val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition)
|
||||||
|
|
||||||
@@ -52,94 +52,18 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
|
|
||||||
fun ConstraintKind.toBound() = if (this == SUB_TYPE) UPPER_BOUND else EXACT_BOUND
|
fun ConstraintKind.toBound() = if (this == SUB_TYPE) UPPER_BOUND else EXACT_BOUND
|
||||||
|
|
||||||
private val allTypeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
|
internal val allTypeParameterBounds = LinkedHashMap<TypeParameterDescriptor, TypeBoundsImpl>()
|
||||||
private val externalTypeParameters = HashSet<TypeParameterDescriptor>()
|
internal val externalTypeParameters = HashSet<TypeParameterDescriptor>()
|
||||||
private val localTypeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>
|
internal val cachedTypeForVariable = HashMap<TypeParameterDescriptor, KotlinType>()
|
||||||
get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds
|
internal val usedInBounds = HashMap<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>()
|
||||||
else allTypeParameterBounds.filter { !externalTypeParameters.contains(it.key) }
|
internal val errors = ArrayList<ConstraintError>()
|
||||||
|
internal val initialConstraints = ArrayList<Constraint>()
|
||||||
private val cachedTypeForVariable = HashMap<TypeParameterDescriptor, KotlinType>()
|
internal val originalToVariables = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
|
||||||
|
internal val variablesToOriginal = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
|
||||||
private val usedInBounds = HashMap<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>()
|
|
||||||
|
|
||||||
private val errors = ArrayList<ConstraintError>()
|
|
||||||
|
|
||||||
private val initialConstraints = ArrayList<Constraint>()
|
|
||||||
|
|
||||||
private val originalToVariablesSubstitutor: TypeSubstitutor by lazy {
|
private val originalToVariablesSubstitutor: TypeSubstitutor by lazy {
|
||||||
createTypeSubstitutor { originalToVariables[it] }
|
createTypeSubstitutor { originalToVariables[it] }
|
||||||
}
|
}
|
||||||
private val originalToVariables = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
|
|
||||||
private val variablesToOriginal = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
|
|
||||||
|
|
||||||
private val constraintSystemStatus = object : ConstraintSystemStatus {
|
|
||||||
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
|
|
||||||
|
|
||||||
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters()
|
|
||||||
|
|
||||||
override fun hasContradiction() = hasParameterConstraintError() || hasConflictingConstraints()
|
|
||||||
|| hasCannotCaptureTypesError() || hasTypeInferenceIncorporationError()
|
|
||||||
|
|
||||||
|
|
||||||
override fun hasViolatedUpperBound() = !isSuccessful() && filterConstraintsOut(TYPE_BOUND_POSITION).getStatus().isSuccessful()
|
|
||||||
|
|
||||||
override fun hasConflictingConstraints() = localTypeParameterBounds.values().any { it.values.size() > 1 }
|
|
||||||
|
|
||||||
override fun hasUnknownParameters() =
|
|
||||||
localTypeParameterBounds.values().any { it.values.isEmpty() } || hasTypeParameterWithUnsatisfiedOnlyInputTypesError()
|
|
||||||
|
|
||||||
override fun hasParameterConstraintError() = errors.any { it is ParameterConstraintError }
|
|
||||||
|
|
||||||
override fun hasOnlyErrorsDerivedFrom(kind: ConstraintPositionKind): Boolean {
|
|
||||||
if (isSuccessful()) return false
|
|
||||||
if (filterConstraintsOut(kind).getStatus().isSuccessful()) return true
|
|
||||||
return errors.isNotEmpty() && errors.all { it.constraintPosition.derivedFrom(kind) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hasErrorInConstrainingTypes() = errors.any { it is ErrorInConstrainingType }
|
|
||||||
|
|
||||||
override fun hasCannotCaptureTypesError() = errors.any { it is CannotCapture }
|
|
||||||
|
|
||||||
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
|
|
||||||
|
|
||||||
override fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError() =
|
|
||||||
localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null }
|
|
||||||
|
|
||||||
override val constraintErrors: List<ConstraintError>
|
|
||||||
get() = errors
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getParameterToInferredValueMap(
|
|
||||||
typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>,
|
|
||||||
getDefaultTypeProjection: (TypeParameterDescriptor) -> TypeProjection,
|
|
||||||
substituteOriginal: Boolean
|
|
||||||
): Map<TypeParameterDescriptor, TypeProjection> {
|
|
||||||
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
|
|
||||||
for ((variable, typeBounds) in typeParameterBounds) {
|
|
||||||
val typeProjection: TypeProjection
|
|
||||||
val value = typeBounds.value
|
|
||||||
val typeParameter = if (substituteOriginal) variablesToOriginal[variable]!! else variable
|
|
||||||
if (value != null && !TypeUtils.containsSpecialType(value, DONT_CARE)) {
|
|
||||||
typeProjection = TypeProjectionImpl(value)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
typeProjection = getDefaultTypeProjection(typeParameter)
|
|
||||||
}
|
|
||||||
substitutionContext.put(typeParameter, typeProjection)
|
|
||||||
}
|
|
||||||
return substitutionContext
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun replaceUninferredBy(
|
|
||||||
getDefaultValue: (TypeParameterDescriptor) -> TypeProjection,
|
|
||||||
substituteOriginal: Boolean
|
|
||||||
): TypeSubstitutor {
|
|
||||||
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
|
|
||||||
val substitution = TypeConstructorSubstitution.createByParametersMap(parameterToInferredValueMap)
|
|
||||||
return SubstitutionFilteringInternalResolveAnnotations(substitution).buildSubstitutor()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getStatus(): ConstraintSystemStatus = constraintSystemStatus
|
|
||||||
|
|
||||||
override fun registerTypeVariables(
|
override fun registerTypeVariables(
|
||||||
typeVariables: Collection<TypeParameterDescriptor>,
|
typeVariables: Collection<TypeParameterDescriptor>,
|
||||||
@@ -172,30 +96,12 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables()
|
type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getNestedTypeVariables(type: KotlinType, original: Boolean): List<TypeParameterDescriptor> {
|
fun getNestedTypeVariables(type: KotlinType, original: Boolean): List<TypeParameterDescriptor> {
|
||||||
return type.getNestedArguments().map { typeProjection ->
|
return type.getNestedArguments().map { typeProjection ->
|
||||||
typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||||
}.filterNotNull().filter { if (original) it in originalToVariables.keys else it in getAllTypeVariables() }
|
}.filterNotNull().filter { if (original) it in originalToVariables.keys else it in getAllTypeVariables() }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun copy(filterConstraintPosition: (ConstraintPosition) -> Boolean): ConstraintSystem {
|
|
||||||
val newSystem = ConstraintSystemImpl()
|
|
||||||
for ((typeParameter, typeBounds) in allTypeParameterBounds) {
|
|
||||||
newSystem.allTypeParameterBounds.put(typeParameter, typeBounds.filter(filterConstraintPosition))
|
|
||||||
}
|
|
||||||
newSystem.usedInBounds.putAll(usedInBounds.map {
|
|
||||||
val (variable, bounds) = it
|
|
||||||
variable to bounds.filterTo(arrayListOf<Bound>()) { filterConstraintPosition(it.position )}
|
|
||||||
}.toMap())
|
|
||||||
newSystem.externalTypeParameters.addAll(externalTypeParameters )
|
|
||||||
newSystem.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
|
|
||||||
|
|
||||||
newSystem.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) })
|
|
||||||
newSystem.originalToVariables.putAll(originalToVariables)
|
|
||||||
newSystem.variablesToOriginal.putAll(variablesToOriginal)
|
|
||||||
return newSystem
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
|
override fun addSupertypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType, constraintPosition: ConstraintPosition) {
|
||||||
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
|
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
|
||||||
|
|
||||||
@@ -423,13 +329,11 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
addBound(typeVariable, capturedType, EXACT_BOUND, constraintContext)
|
addBound(typeVariable, capturedType, EXACT_BOUND, constraintContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTypeVariables() = originalToVariables.keySet()
|
|
||||||
|
|
||||||
fun getAllTypeVariables() = allTypeParameterBounds.keySet()
|
fun getAllTypeVariables() = allTypeParameterBounds.keySet()
|
||||||
|
|
||||||
fun getBoundsUsedIn(typeVariable: TypeParameterDescriptor): List<Bound> = usedInBounds[typeVariable] ?: emptyList()
|
fun getBoundsUsedIn(typeVariable: TypeParameterDescriptor): List<Bound> = usedInBounds[typeVariable] ?: emptyList()
|
||||||
|
|
||||||
override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl {
|
fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl {
|
||||||
val variableForOriginal = originalToVariables[typeVariable]
|
val variableForOriginal = originalToVariables[typeVariable]
|
||||||
if (variableForOriginal != null && variableForOriginal != typeVariable) {
|
if (variableForOriginal != null && variableForOriginal != typeVariable) {
|
||||||
return getTypeBounds(variableForOriginal)
|
return getTypeBounds(variableForOriginal)
|
||||||
@@ -449,42 +353,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
return if (typeParameterDescriptor != null && isMyTypeVariable(typeParameterDescriptor)) typeParameterDescriptor else null
|
return if (typeParameterDescriptor != null && isMyTypeVariable(typeParameterDescriptor)) typeParameterDescriptor else null
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getResultingSubstitutor() =
|
|
||||||
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
|
||||||
|
|
||||||
override fun getCurrentSubstitutor() =
|
|
||||||
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(TypeUtils.DONT_CARE) }
|
|
||||||
|
|
||||||
override fun getPartialSubstitutor() =
|
|
||||||
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(it.correspondingType) }
|
|
||||||
|
|
||||||
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeParameterDescriptor) -> TypeProjection) =
|
|
||||||
replaceUninferredBy(getDefaultValue, substituteOriginal).setApproximateCapturedTypes()
|
|
||||||
|
|
||||||
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: KotlinType, superType: KotlinType, position: ConstraintPosition) {
|
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: KotlinType, superType: KotlinType, position: ConstraintPosition) {
|
||||||
initialConstraints.add(Constraint(constraintKind, subType, superType, position))
|
initialConstraints.add(Constraint(constraintKind, subType, superType, position))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun satisfyInitialConstraints(): Boolean {
|
|
||||||
fun KotlinType.substitute(): KotlinType? {
|
|
||||||
val substitutor = getSubstitutor(substituteOriginal = false) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
|
||||||
return substitutor.substitute(this, Variance.INVARIANT) ?: return null
|
|
||||||
}
|
|
||||||
return initialConstraints.all {
|
|
||||||
constraint ->
|
|
||||||
val resultSubType = constraint.subtype.substitute()?.let {
|
|
||||||
// the call might be done via safe access, so we check for notNullable receiver type;
|
|
||||||
// 'unsafe call' error is reported otherwise later
|
|
||||||
if (constraint.position.kind != ConstraintPositionKind.RECEIVER_POSITION) it else it.makeNotNullable()
|
|
||||||
} ?: return false
|
|
||||||
val resultSuperType = constraint.superType.substitute() ?: return false
|
|
||||||
when (constraint.kind) {
|
|
||||||
SUB_TYPE -> KotlinTypeChecker.DEFAULT.isSubtypeOf(resultSubType, resultSuperType)
|
|
||||||
EQUAL -> KotlinTypeChecker.DEFAULT.equalTypes(resultSubType, resultSuperType)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fixVariable(typeVariable: TypeParameterDescriptor) {
|
fun fixVariable(typeVariable: TypeParameterDescriptor) {
|
||||||
val typeBounds = getTypeBounds(typeVariable)
|
val typeBounds = getTypeBounds(typeVariable)
|
||||||
if (typeBounds.isFixed) return
|
if (typeBounds.isFixed) return
|
||||||
@@ -505,6 +377,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
functionTypeParameters.forEach { fixVariable(it) }
|
functionTypeParameters.forEach { fixVariable(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun build(): ConstraintSystem {
|
||||||
|
return ConstraintSystemSnapshot(allTypeParameterBounds, externalTypeParameters, usedInBounds, errors, initialConstraints,
|
||||||
|
originalToVariables, variablesToOriginal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTypeForFunctionPlaceholder(
|
fun createTypeForFunctionPlaceholder(
|
||||||
@@ -532,7 +408,7 @@ fun createTypeForFunctionPlaceholder(
|
|||||||
return functionPlaceholder.builtIns.getFunctionType(Annotations.EMPTY, receiverType, newArgumentTypes, DONT_CARE)
|
return functionPlaceholder.builtIns.getFunctionType(Annotations.EMPTY, receiverType, newArgumentTypes, DONT_CARE)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TypeSubstitutor.setApproximateCapturedTypes(): TypeSubstitutor {
|
internal fun TypeSubstitutor.setApproximateCapturedTypes(): TypeSubstitutor {
|
||||||
return TypeSubstitutor.create(SubstitutionWithCapturedTypeApproximation(getSubstitution()))
|
return TypeSubstitutor.create(SubstitutionWithCapturedTypeApproximation(getSubstitution()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.SUB_TYPE
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.TYPE_BOUND_POSITION
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.derivedFrom
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation
|
||||||
|
import org.jetbrains.kotlin.resolve.scopes.KtScope
|
||||||
|
import org.jetbrains.kotlin.types.*
|
||||||
|
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||||
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.getNestedArguments
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class ConstraintSystemSnapshot(
|
||||||
|
private val allTypeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>,
|
||||||
|
private val externalTypeParameters: Set<TypeParameterDescriptor>,
|
||||||
|
private val usedInBounds: Map<TypeParameterDescriptor, MutableList<TypeBounds.Bound>>,
|
||||||
|
private val errors: List<ConstraintError>,
|
||||||
|
private val initialConstraints: List<ConstraintSystemImpl.Constraint>,
|
||||||
|
private val originalToVariables: Map<TypeParameterDescriptor, TypeParameterDescriptor>,
|
||||||
|
private val variablesToOriginal: Map<TypeParameterDescriptor, TypeParameterDescriptor>
|
||||||
|
) : ConstraintSystem {
|
||||||
|
private val localTypeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>
|
||||||
|
get() = if (externalTypeParameters.isEmpty()) allTypeParameterBounds
|
||||||
|
else allTypeParameterBounds.filter { !externalTypeParameters.contains(it.key) }
|
||||||
|
|
||||||
|
private val constraintSystemStatus = object : ConstraintSystemStatus {
|
||||||
|
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
|
||||||
|
|
||||||
|
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters()
|
||||||
|
|
||||||
|
override fun hasContradiction() = hasParameterConstraintError() || hasConflictingConstraints()
|
||||||
|
|| hasCannotCaptureTypesError() || hasTypeInferenceIncorporationError()
|
||||||
|
|
||||||
|
override fun hasViolatedUpperBound() = !isSuccessful() && filterConstraintsOut(TYPE_BOUND_POSITION).getStatus().isSuccessful()
|
||||||
|
|
||||||
|
override fun hasConflictingConstraints() = localTypeParameterBounds.values.any { it.values.size > 1 }
|
||||||
|
|
||||||
|
override fun hasUnknownParameters() =
|
||||||
|
localTypeParameterBounds.values.any { it.values.isEmpty() } || hasTypeParameterWithUnsatisfiedOnlyInputTypesError()
|
||||||
|
|
||||||
|
override fun hasParameterConstraintError() = errors.any { it is ParameterConstraintError }
|
||||||
|
|
||||||
|
override fun hasOnlyErrorsDerivedFrom(kind: ConstraintPositionKind): Boolean {
|
||||||
|
if (isSuccessful()) return false
|
||||||
|
if (filterConstraintsOut(kind).getStatus().isSuccessful()) return true
|
||||||
|
return errors.isNotEmpty() && errors.all { it.constraintPosition.derivedFrom(kind) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hasErrorInConstrainingTypes() = errors.any { it is ErrorInConstrainingType }
|
||||||
|
|
||||||
|
override fun hasCannotCaptureTypesError() = errors.any { it is CannotCapture }
|
||||||
|
|
||||||
|
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
|
||||||
|
|
||||||
|
override fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError() =
|
||||||
|
localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null }
|
||||||
|
|
||||||
|
override val constraintErrors: List<ConstraintError>
|
||||||
|
get() = errors
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getParameterToInferredValueMap(
|
||||||
|
typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>,
|
||||||
|
getDefaultTypeProjection: (TypeParameterDescriptor) -> TypeProjection,
|
||||||
|
substituteOriginal: Boolean
|
||||||
|
): Map<TypeParameterDescriptor, TypeProjection> {
|
||||||
|
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
|
||||||
|
for ((variable, typeBounds) in typeParameterBounds) {
|
||||||
|
val typeProjection: TypeProjection
|
||||||
|
val value = typeBounds.value
|
||||||
|
val typeParameter = if (substituteOriginal) variablesToOriginal[variable]!! else variable
|
||||||
|
if (value != null && !TypeUtils.containsSpecialType(value, DONT_CARE)) {
|
||||||
|
typeProjection = TypeProjectionImpl(value)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
typeProjection = getDefaultTypeProjection(typeParameter)
|
||||||
|
}
|
||||||
|
substitutionContext.put(typeParameter, typeProjection)
|
||||||
|
}
|
||||||
|
return substitutionContext
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun replaceUninferredBy(
|
||||||
|
getDefaultValue: (TypeParameterDescriptor) -> TypeProjection,
|
||||||
|
substituteOriginal: Boolean
|
||||||
|
): TypeSubstitutor {
|
||||||
|
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
|
||||||
|
val substitution = TypeConstructorSubstitution.createByParametersMap(parameterToInferredValueMap)
|
||||||
|
return SubstitutionFilteringInternalResolveAnnotations(substitution).buildSubstitutor()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getStatus(): ConstraintSystemStatus = constraintSystemStatus
|
||||||
|
|
||||||
|
override fun getNestedTypeVariables(type: KotlinType): List<TypeParameterDescriptor> {
|
||||||
|
return type.getNestedArguments().map { typeProjection ->
|
||||||
|
typeProjection.type.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||||
|
}.filterNotNull().filter { it in getTypeVariables() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTypeVariables() = originalToVariables.keys
|
||||||
|
|
||||||
|
override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl {
|
||||||
|
val variableForOriginal = originalToVariables[typeVariable]
|
||||||
|
if (variableForOriginal != null && variableForOriginal != typeVariable) {
|
||||||
|
return getTypeBounds(variableForOriginal)
|
||||||
|
}
|
||||||
|
return allTypeParameterBounds[typeVariable] ?:
|
||||||
|
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getResultingSubstitutor() =
|
||||||
|
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
||||||
|
|
||||||
|
override fun getCurrentSubstitutor() =
|
||||||
|
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(TypeUtils.DONT_CARE) }
|
||||||
|
|
||||||
|
override fun getPartialSubstitutor() =
|
||||||
|
getSubstitutor(substituteOriginal = true) {
|
||||||
|
TypeProjectionImpl(KotlinTypeImpl.create(Annotations.EMPTY, it.typeConstructor, false, listOf(), KtScope.Empty))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeParameterDescriptor) -> TypeProjection) =
|
||||||
|
replaceUninferredBy(getDefaultValue, substituteOriginal).setApproximateCapturedTypes()
|
||||||
|
|
||||||
|
private fun satisfyInitialConstraints(): Boolean {
|
||||||
|
fun KotlinType.substitute(): KotlinType? {
|
||||||
|
val substitutor = getSubstitutor(substituteOriginal = false) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
||||||
|
return substitutor.substitute(this, Variance.INVARIANT) ?: return null
|
||||||
|
}
|
||||||
|
return initialConstraints.all {
|
||||||
|
constraint ->
|
||||||
|
val resultSubType = constraint.subtype.substitute()?.let {
|
||||||
|
// the call might be done via safe access, so we check for notNullable receiver type;
|
||||||
|
// 'unsafe call' error is reported otherwise later
|
||||||
|
if (constraint.position.kind != ConstraintPositionKind.RECEIVER_POSITION) it else it.makeNotNullable()
|
||||||
|
} ?: return false
|
||||||
|
val resultSuperType = constraint.superType.substitute() ?: return false
|
||||||
|
when (constraint.kind) {
|
||||||
|
SUB_TYPE -> KotlinTypeChecker.DEFAULT.isSubtypeOf(resultSubType, resultSuperType)
|
||||||
|
EQUAL -> KotlinTypeChecker.DEFAULT.equalTypes(resultSubType, resultSuperType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toBuilder(filterConstraintPosition: (ConstraintPosition) -> Boolean): ConstraintSystem.Builder {
|
||||||
|
val result = ConstraintSystemImpl()
|
||||||
|
for ((typeParameter, typeBounds) in allTypeParameterBounds) {
|
||||||
|
result.allTypeParameterBounds.put(typeParameter, typeBounds.filter(filterConstraintPosition))
|
||||||
|
}
|
||||||
|
result.usedInBounds.putAll(usedInBounds.map {
|
||||||
|
val (variable, bounds) = it
|
||||||
|
variable to bounds.filterTo(arrayListOf<TypeBounds.Bound>()) { filterConstraintPosition(it.position )}
|
||||||
|
}.toMap())
|
||||||
|
result.externalTypeParameters.addAll(externalTypeParameters )
|
||||||
|
result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
|
||||||
|
|
||||||
|
result.initialConstraints.addAll(initialConstraints.filter { filterConstraintPosition(it.position) })
|
||||||
|
result.originalToVariables.putAll(originalToVariables)
|
||||||
|
result.variablesToOriginal.putAll(variablesToOriginal)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
|||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem;
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl;
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
|
import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope;
|
||||||
@@ -184,7 +185,7 @@ public class TypeIntersector {
|
|||||||
};
|
};
|
||||||
processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
|
processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
|
||||||
processAllTypeParameters(expected, Variance.INVARIANT, processor);
|
processAllTypeParameters(expected, Variance.INVARIANT, processor);
|
||||||
ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
|
ConstraintSystem.Builder constraintSystem = new ConstraintSystemImpl();
|
||||||
constraintSystem.registerTypeVariables(parameters.keySet(), new Function1<TypeParameterDescriptor, TypeParameterDescriptor>() {
|
constraintSystem.registerTypeVariables(parameters.keySet(), new Function1<TypeParameterDescriptor, TypeParameterDescriptor>() {
|
||||||
@Override
|
@Override
|
||||||
public TypeParameterDescriptor invoke(TypeParameterDescriptor descriptor) {
|
public TypeParameterDescriptor invoke(TypeParameterDescriptor descriptor) {
|
||||||
@@ -193,7 +194,7 @@ public class TypeIntersector {
|
|||||||
}, false);
|
}, false);
|
||||||
constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position());
|
constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position());
|
||||||
|
|
||||||
return constraintSystem.getStatus().isSuccessful();
|
return constraintSystem.build().getStatus().isSuccessful();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processAllTypeParameters(KotlinType type, Variance howThisTypeIsUsed, Function1<TypeParameterUsage, Unit> result) {
|
private static void processAllTypeParameters(KotlinType type, Variance howThisTypeIsUsed, Function1<TypeParameterUsage, Unit> result) {
|
||||||
|
|||||||
+11
-8
@@ -76,12 +76,12 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() {
|
|||||||
val constraintsFile = File(filePath)
|
val constraintsFile = File(filePath)
|
||||||
val constraintsFileText = constraintsFile.readLines()
|
val constraintsFileText = constraintsFile.readLines()
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
val builder = ConstraintSystemImpl()
|
||||||
|
|
||||||
val variables = parseVariables(constraintsFileText)
|
val variables = parseVariables(constraintsFileText)
|
||||||
val fixVariables = constraintsFileText.contains("FIX_VARIABLES")
|
val fixVariables = constraintsFileText.contains("FIX_VARIABLES")
|
||||||
val typeParameterDescriptors = variables.map { testDeclarations.getParameterDescriptor(it) }
|
val typeParameterDescriptors = variables.map { testDeclarations.getParameterDescriptor(it) }
|
||||||
constraintSystem.registerTypeVariables(typeParameterDescriptors)
|
builder.registerTypeVariables(typeParameterDescriptors)
|
||||||
|
|
||||||
val constraints = parseConstraints(constraintsFileText)
|
val constraints = parseConstraints(constraintsFileText)
|
||||||
fun KotlinType.assertNotError(): KotlinType {
|
fun KotlinType.assertNotError(): KotlinType {
|
||||||
@@ -93,17 +93,20 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() {
|
|||||||
val secondType = testDeclarations.getType(constraint.secondType).assertNotError()
|
val secondType = testDeclarations.getType(constraint.secondType).assertNotError()
|
||||||
val context = ConstraintContext(SPECIAL.position(), initial = true)
|
val context = ConstraintContext(SPECIAL.position(), initial = true)
|
||||||
when (constraint.kind) {
|
when (constraint.kind) {
|
||||||
MyConstraintKind.SUBTYPE -> constraintSystem.addSubtypeConstraint(firstType, secondType, context.position)
|
MyConstraintKind.SUBTYPE -> builder.addSubtypeConstraint(firstType, secondType, context.position)
|
||||||
MyConstraintKind.SUPERTYPE -> constraintSystem.addSupertypeConstraint(firstType, secondType, context.position)
|
MyConstraintKind.SUPERTYPE -> builder.addSupertypeConstraint(firstType, secondType, context.position)
|
||||||
MyConstraintKind.EQUAL -> constraintSystem.addConstraint(
|
MyConstraintKind.EQUAL -> builder.addConstraint(
|
||||||
ConstraintSystemImpl.ConstraintKind.EQUAL, firstType, secondType, context)
|
ConstraintSystemImpl.ConstraintKind.EQUAL, firstType, secondType, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fixVariables) constraintSystem.fixVariables()
|
|
||||||
|
|
||||||
val resultingStatus = Renderers.RENDER_CONSTRAINT_SYSTEM_SHORT.render(constraintSystem)
|
if (fixVariables) builder.fixVariables()
|
||||||
|
|
||||||
val resultingSubstitutor = constraintSystem.getResultingSubstitutor()
|
val system = builder.build()
|
||||||
|
|
||||||
|
val resultingStatus = Renderers.RENDER_CONSTRAINT_SYSTEM_SHORT.render(system)
|
||||||
|
|
||||||
|
val resultingSubstitutor = system.getResultingSubstitutor()
|
||||||
val result = typeParameterDescriptors.map {
|
val result = typeParameterDescriptors.map {
|
||||||
val parameterType = testDeclarations.getType(it.getName().asString())
|
val parameterType = testDeclarations.getType(it.getName().asString())
|
||||||
val resultType = resultingSubstitutor.substitute(parameterType, Variance.INVARIANT)
|
val resultType = resultingSubstitutor.substitute(parameterType, Variance.INVARIANT)
|
||||||
|
|||||||
@@ -116,16 +116,18 @@ class FuzzyType(
|
|||||||
return if (type.checkInheritance(otherType.type)) TypeSubstitutor.EMPTY else null
|
return if (type.checkInheritance(otherType.type)) TypeSubstitutor.EMPTY else null
|
||||||
}
|
}
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
val builder = ConstraintSystemImpl()
|
||||||
constraintSystem.registerTypeVariables(freeParameters)
|
builder.registerTypeVariables(freeParameters)
|
||||||
constraintSystem.registerTypeVariables(otherType.freeParameters)
|
builder.registerTypeVariables(otherType.freeParameters)
|
||||||
|
|
||||||
when (matchKind) {
|
when (matchKind) {
|
||||||
MatchKind.IS_SUBTYPE -> constraintSystem.addSubtypeConstraint(type, otherType.type, ConstraintPositionKind.RECEIVER_POSITION.position())
|
MatchKind.IS_SUBTYPE -> builder.addSubtypeConstraint(type, otherType.type, ConstraintPositionKind.RECEIVER_POSITION.position())
|
||||||
MatchKind.IS_SUPERTYPE -> constraintSystem.addSubtypeConstraint(otherType.type, type, ConstraintPositionKind.RECEIVER_POSITION.position())
|
MatchKind.IS_SUPERTYPE -> builder.addSubtypeConstraint(otherType.type, type, ConstraintPositionKind.RECEIVER_POSITION.position())
|
||||||
}
|
}
|
||||||
|
|
||||||
constraintSystem.fixVariables()
|
builder.fixVariables()
|
||||||
|
|
||||||
|
val constraintSystem = builder.build()
|
||||||
|
|
||||||
if (constraintSystem.getStatus().hasContradiction()) return null
|
if (constraintSystem.getStatus().hasContradiction()) return null
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user