Always alpha-convert non-external type parameters before registering in system
This commit is contained in:
+1
-11
@@ -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)
|
||||||
|
|
||||||
|
|||||||
+3
-7
@@ -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.
|
||||||
|
|||||||
+18
-8
@@ -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();
|
||||||
|
|||||||
+13
-10
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user