Always alpha-convert non-external type parameters before registering in system

This commit is contained in:
Alexander Udalov
2015-11-06 19:01:42 +03:00
parent 4d5d24a503
commit 27ce61a3be
6 changed files with 47 additions and 47 deletions
@@ -56,17 +56,7 @@ class GenericCandidateResolver(private val argumentTypeResolver: ArgumentTypeRes
val candidate = candidateCall.candidateDescriptor val candidate = candidateCall.candidateDescriptor
val builder = ConstraintSystemBuilderImpl() val builder = ConstraintSystemBuilderImpl()
builder.registerTypeVariables(candidate.typeParameters)
// If the call is recursive, e.g.
// fun foo<T>(t : T) : T = foo(t)
// we can't use same descriptor objects for T's as actual type values and same T's as unknowns,
// because constraints become trivial (T :< T), and inference fails
//
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
val conversionToOriginal = candidateWithFreshVariables.typeParameters.zip(candidate.typeParameters).toMap()
builder.registerTypeVariables(candidateWithFreshVariables.typeParameters, { conversionToOriginal[it]!! })
val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE) val substituteDontCare = makeConstantSubstitutor(candidate.typeParameters, DONT_CARE)
@@ -65,14 +65,10 @@ interface ConstraintSystem {
interface Builder { interface Builder {
/** /**
* Registers variables in a constraint system. * Registers variables in a constraint system. Returns a substitutor which maps type parameter descriptors given as parameters
* The type variables for the corresponding function are local, the type variables of inner arguments calls are non-local. * to the corresponding type variables of the system. Use that substitutor to provide constraints to the system
*/ */
fun registerTypeVariables( fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>, external: Boolean = false): TypeSubstitutor
typeVariables: Collection<TypeParameterDescriptor>,
mapToDescriptor: (TypeParameterDescriptor) -> TypeParameterDescriptor = { it },
external: Boolean = false
)
/** /**
* Adds a constraint that the constraining type is a subtype of the subject type. * Adds a constraint that the constraining type is a subtype of the subject type.
@@ -67,19 +67,25 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
}) })
} }
override fun registerTypeVariables( override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>, external: Boolean): TypeSubstitutor {
typeVariables: Collection<TypeParameterDescriptor>, if (typeParameters.isEmpty()) return TypeSubstitutor.EMPTY
mapToDescriptor: (TypeParameterDescriptor) -> TypeParameterDescriptor,
external: Boolean
) {
if (external) externalTypeParameters.addAll(typeVariables)
for (typeVariable in typeVariables) { val typeVariables = if (external) {
externalTypeParameters.addAll(typeParameters)
typeParameters.toList()
}
else ArrayList<TypeParameterDescriptor>(typeParameters.size).apply {
DescriptorSubstitutor.substituteTypeParameters(
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, this
)
}
for ((descriptor, typeVariable) in typeParameters.zip(typeVariables)) {
allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable)) allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable))
val descriptor = mapToDescriptor(typeVariable)
descriptorToVariable[descriptor] = typeVariable descriptorToVariable[descriptor] = typeVariable
variableToDescriptor[typeVariable] = descriptor variableToDescriptor[typeVariable] = descriptor
} }
for ((typeVariable, typeBounds) in allTypeParameterBounds) { for ((typeVariable, typeBounds) in allTypeParameterBounds) {
for (declaredUpperBound in typeVariable.upperBounds) { for (declaredUpperBound in typeVariable.upperBounds) {
if (declaredUpperBound.isDefaultBound()) continue //todo remove this line (?) if (declaredUpperBound.isDefaultBound()) continue //todo remove this line (?)
@@ -87,6 +93,10 @@ class ConstraintSystemBuilderImpl : ConstraintSystem.Builder {
addBound(typeVariable, declaredUpperBound, UPPER_BOUND, context) addBound(typeVariable, declaredUpperBound, UPPER_BOUND, context)
} }
} }
return TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap(
typeParameters.zip(TypeUtils.getDefaultTypeProjections(typeVariables)).toMap()
))
} }
internal val TypeParameterDescriptor.correspondingType: KotlinType internal val TypeParameterDescriptor.correspondingType: KotlinType
@@ -22,7 +22,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns; import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor; import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
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.ConstraintSystem;
@@ -186,12 +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);
ConstraintSystem.Builder constraintSystem = new ConstraintSystemBuilderImpl(); ConstraintSystem.Builder constraintSystem = new ConstraintSystemBuilderImpl();
constraintSystem.registerTypeVariables(parameters.keySet(), new Function1<TypeParameterDescriptor, TypeParameterDescriptor>() { constraintSystem.registerTypeVariables(parameters.keySet(), false);
@Override
public TypeParameterDescriptor invoke(TypeParameterDescriptor descriptor) {
return descriptor;
}
}, false);
constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position()); constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position());
return constraintSystem.build().getStatus().isSuccessful(); return constraintSystem.build().getStatus().isSuccessful();
@@ -81,16 +81,20 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() {
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) }
builder.registerTypeVariables(typeParameterDescriptors) val substitutor = builder.registerTypeVariables(typeParameterDescriptors)
val constraints = parseConstraints(constraintsFileText) val constraints = parseConstraints(constraintsFileText)
fun KotlinType.assertNotError(): KotlinType {
assert(!ErrorUtils.containsErrorType(this)) { "Type $this is resolved to or contains error type" } fun getType(typeString: String): KotlinType {
return this val type = testDeclarations.getType(typeString).apply {
assert(!ErrorUtils.containsErrorType(this)) { "Type $this is resolved to or contains error type" }
}
return substitutor.substitute(type, Variance.INVARIANT) ?: error("Failed to substitute $type")
} }
for (constraint in constraints) { for (constraint in constraints) {
val firstType = testDeclarations.getType(constraint.firstType).assertNotError() val firstType = getType(constraint.firstType)
val secondType = testDeclarations.getType(constraint.secondType).assertNotError() val secondType = getType(constraint.secondType)
val context = ConstraintContext(SPECIAL.position(), initial = true) val context = ConstraintContext(SPECIAL.position(), initial = true)
when (constraint.kind) { when (constraint.kind) {
MyConstraintKind.SUBTYPE -> builder.addSubtypeConstraint(firstType, secondType, context.position) MyConstraintKind.SUBTYPE -> builder.addSubtypeConstraint(firstType, secondType, context.position)
@@ -118,8 +122,7 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() {
} }
class MyConstraint(val kind: MyConstraintKind, val firstType: String, val secondType: String) class MyConstraint(val kind: MyConstraintKind, val firstType: String, val secondType: String)
enum class MyConstraintKind enum class MyConstraintKind(val token: String) {
private constructor(val token: String) {
SUBTYPE("<:"), SUPERTYPE(">:"), EQUAL(":=") SUBTYPE("<:"), SUPERTYPE(">:"), EQUAL(":=")
} }
@@ -132,8 +135,8 @@ abstract public class AbstractConstraintSystemTest() : KotlinLiteFixture() {
} }
private fun parseConstraints(lines: List<String>): List<MyConstraint> { private fun parseConstraints(lines: List<String>): List<MyConstraint> {
val kindsMap = MyConstraintKind.values().map { it.token to it }.toMap() val kindsMap = MyConstraintKind.values.map { it.token to it }.toMap()
val kinds = kindsMap.keySet() val kinds = kindsMap.keys
val linesWithConstraints = lines.filter { line -> kinds.any { kind -> line.contains(kind) } } val linesWithConstraints = lines.filter { line -> kinds.any { kind -> line.contains(kind) } }
return linesWithConstraints.map { return linesWithConstraints.map {
line -> line ->
@@ -115,12 +115,19 @@ class FuzzyType(
} }
val builder = ConstraintSystemBuilderImpl() val builder = ConstraintSystemBuilderImpl()
builder.registerTypeVariables(freeParameters) val typeVariableSubstitutor = builder.registerTypeVariables(freeParameters + otherType.freeParameters)
builder.registerTypeVariables(otherType.freeParameters)
when (matchKind) { when (matchKind) {
MatchKind.IS_SUBTYPE -> builder.addSubtypeConstraint(type, otherType.type, ConstraintPositionKind.RECEIVER_POSITION.position()) MatchKind.IS_SUBTYPE -> builder.addSubtypeConstraint(
MatchKind.IS_SUPERTYPE -> builder.addSubtypeConstraint(otherType.type, type, ConstraintPositionKind.RECEIVER_POSITION.position()) typeVariableSubstitutor.substitute(type, Variance.INVARIANT),
otherType.type,
ConstraintPositionKind.RECEIVER_POSITION.position()
)
MatchKind.IS_SUPERTYPE -> builder.addSubtypeConstraint(
typeVariableSubstitutor.substitute(otherType.type, Variance.INVARIANT),
type,
ConstraintPositionKind.RECEIVER_POSITION.position()
)
} }
builder.fixVariables() builder.fixVariables()