Move mutating methods of ConstraintSystem to Builder

Extract immutable ConstraintSystemSnapshot from ConstraintSystemImpl
This commit is contained in:
Alexander Udalov
2015-10-29 19:42:19 +03:00
parent d320922e08
commit bb918a2742
11 changed files with 323 additions and 238 deletions
@@ -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 }
} }
@@ -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
@@ -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()
} }
@@ -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
); );
} }
@@ -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()))
} }
@@ -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) {
@@ -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