Solve the constraint system for alpha-converted variables,
store initial and backward conversions for substituting new constraints and the result
This commit is contained in:
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
|||||||
import org.jetbrains.kotlin.psi.JetSuperExpression
|
import org.jetbrains.kotlin.psi.JetSuperExpression
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.EXPECTED_TYPE_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
import org.jetbrains.kotlin.types.*
|
import org.jetbrains.kotlin.types.*
|
||||||
@@ -64,22 +65,17 @@ public fun replaceReturnTypeByUnknown(type: JetType): JetType {
|
|||||||
return JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isMarkedNullable(), newArguments, type.getMemberScope())
|
return JetTypeImpl(type.getAnnotations(), type.getConstructor(), type.isMarkedNullable(), newArguments, type.getMemberScope())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun hasReturnTypeDependentOnUninferredParams(candidateDescriptor: CallableDescriptor, constraintSystem: ConstraintSystem): Boolean {
|
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
||||||
val returnType = candidateDescriptor.getReturnType() ?: return false
|
val returnType = getReturnType() ?: return false
|
||||||
|
|
||||||
for (typeVariable in constraintSystem.getTypeVariables()) {
|
val nestedTypeVariables = with (constraintSystem as ConstraintSystemImpl) {
|
||||||
val inferredValueForTypeVariable = constraintSystem.getTypeBounds(typeVariable).value
|
returnType.getNestedTypeVariables(original = true)
|
||||||
if (inferredValueForTypeVariable == null) {
|
|
||||||
if (TypeUtils.dependsOnTypeParameters(returnType, setOf(typeVariable))) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false
|
return nestedTypeVariables.any { constraintSystem.getTypeBounds(it).value == null }
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun hasInferredReturnType(candidateDescriptor: CallableDescriptor, constraintSystem: ConstraintSystem): Boolean {
|
public fun CallableDescriptor.hasInferredReturnType(constraintSystem: ConstraintSystem): Boolean {
|
||||||
if (hasReturnTypeDependentOnUninferredParams(candidateDescriptor, constraintSystem)) return false
|
if (hasReturnTypeDependentOnUninferredParams(constraintSystem)) return false
|
||||||
|
|
||||||
// Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
|
// Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
|
||||||
if (constraintSystem.getStatus().hasOnlyErrorsFromPosition(EXPECTED_TYPE_POSITION.position())) return false
|
if (constraintSystem.getStatus().hasOnlyErrorsFromPosition(EXPECTED_TYPE_POSITION.position())) return false
|
||||||
|
|||||||
+9
-13
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.calls.context.TemporaryTraceAndCache
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystem
|
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.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.RECEIVER_POSITION
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.RECEIVER_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.VALUE_PARAMETER_POSITION
|
||||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||||
@@ -62,6 +63,7 @@ class GenericCandidateResolver(
|
|||||||
val candidate = candidateCall.getCandidateDescriptor()
|
val candidate = candidateCall.getCandidateDescriptor()
|
||||||
|
|
||||||
val constraintSystem = ConstraintSystemImpl()
|
val constraintSystem = 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)
|
||||||
@@ -71,16 +73,15 @@ class GenericCandidateResolver(
|
|||||||
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
// Thus, we replace the parameters of our descriptor with fresh objects (perform alpha-conversion)
|
||||||
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
val candidateWithFreshVariables = FunctionDescriptorUtil.alphaConvertTypeParameters(candidate)
|
||||||
|
|
||||||
val backConversion = candidateWithFreshVariables.getTypeParameters().zip(candidate.getTypeParameters()).toMap()
|
val conversionToOriginal = candidateWithFreshVariables.getTypeParameters().zip(candidate.getTypeParameters()).toMap()
|
||||||
|
constraintSystem.registerTypeVariables(candidateWithFreshVariables.getTypeParameters(), { Variance.INVARIANT }, { conversionToOriginal[it]!! })
|
||||||
|
|
||||||
constraintSystem.registerTypeVariables(candidateWithFreshVariables.getTypeParameters(), { Variance.INVARIANT })
|
val substituteDontCare = makeConstantSubstitutor(candidate.getTypeParameters(), DONT_CARE)
|
||||||
|
|
||||||
val substituteDontCare = makeConstantSubstitutor(candidateWithFreshVariables.getTypeParameters(), DONT_CARE)
|
|
||||||
|
|
||||||
// Value parameters
|
// Value parameters
|
||||||
for (entry in candidateCall.getValueArguments().entrySet()) {
|
for (entry in candidateCall.getValueArguments().entrySet()) {
|
||||||
val resolvedValueArgument = entry.getValue()
|
val resolvedValueArgument = entry.getValue()
|
||||||
val valueParameterDescriptor = candidateWithFreshVariables.getValueParameters().get(entry.getKey().getIndex())
|
val valueParameterDescriptor = candidate.getValueParameters().get(entry.getKey().getIndex())
|
||||||
|
|
||||||
|
|
||||||
for (valueArgument in resolvedValueArgument.getArguments()) {
|
for (valueArgument in resolvedValueArgument.getArguments()) {
|
||||||
@@ -97,7 +98,7 @@ class GenericCandidateResolver(
|
|||||||
// Receiver
|
// Receiver
|
||||||
// Error is already reported if something is missing
|
// Error is already reported if something is missing
|
||||||
val receiverArgument = candidateCall.getExtensionReceiver()
|
val receiverArgument = candidateCall.getExtensionReceiver()
|
||||||
val receiverParameter = candidateWithFreshVariables.getExtensionReceiverParameter()
|
val receiverParameter = candidate.getExtensionReceiverParameter()
|
||||||
if (receiverArgument.exists() && receiverParameter != null) {
|
if (receiverArgument.exists() && receiverParameter != null) {
|
||||||
var receiverType: JetType? = if (context.candidateCall.isSafeCall())
|
var receiverType: JetType? = if (context.candidateCall.isSafeCall())
|
||||||
TypeUtils.makeNotNullable(receiverArgument.getType())
|
TypeUtils.makeNotNullable(receiverArgument.getType())
|
||||||
@@ -109,11 +110,6 @@ class GenericCandidateResolver(
|
|||||||
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), RECEIVER_POSITION.position())
|
constraintSystem.addSubtypeConstraint(receiverType, receiverParameter.getType(), RECEIVER_POSITION.position())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore type variables before alpha-conversion
|
|
||||||
val constraintSystemWithRightTypeParameters = constraintSystem.substituteTypeVariables { backConversion.get(it) }
|
|
||||||
candidateCall.setConstraintSystem(constraintSystemWithRightTypeParameters)
|
|
||||||
|
|
||||||
|
|
||||||
// Solution
|
// Solution
|
||||||
val hasContradiction = constraintSystem.getStatus().hasContradiction()
|
val hasContradiction = constraintSystem.getStatus().hasContradiction()
|
||||||
if (!hasContradiction) {
|
if (!hasContradiction) {
|
||||||
@@ -168,7 +164,7 @@ class GenericCandidateResolver(
|
|||||||
val returnType = candidateDescriptor.getReturnType() ?: return false
|
val returnType = candidateDescriptor.getReturnType() ?: return false
|
||||||
|
|
||||||
val nestedTypeVariables = with (argumentConstraintSystem) {
|
val nestedTypeVariables = with (argumentConstraintSystem) {
|
||||||
returnType.getNestedTypeVariables()
|
returnType.getNestedTypeVariables(original = true)
|
||||||
}
|
}
|
||||||
// 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
|
||||||
@@ -178,7 +174,7 @@ class GenericCandidateResolver(
|
|||||||
val conversion = candidateDescriptor.getTypeParameters().zip(candidateWithFreshVariables.getTypeParameters()).toMap()
|
val conversion = candidateDescriptor.getTypeParameters().zip(candidateWithFreshVariables.getTypeParameters()).toMap()
|
||||||
|
|
||||||
val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull()
|
val freshVariables = nestedTypeVariables.map { conversion[it] }.filterNotNull()
|
||||||
constraintSystem.registerTypeVariables(freshVariables, { Variance.INVARIANT }, external = true)
|
constraintSystem.registerTypeVariables(freshVariables, { Variance.INVARIANT }, { it }, external = true)
|
||||||
|
|
||||||
constraintSystem.addSubtypeConstraint(candidateWithFreshVariables.getReturnType(), effectiveExpectedType, constraintPosition)
|
constraintSystem.addSubtypeConstraint(candidateWithFreshVariables.getReturnType(), effectiveExpectedType, constraintPosition)
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -15,6 +15,6 @@ class C<X, Z, Y : X>
|
|||||||
|
|
||||||
class D<X, Z, Y : X>(<!UNUSED_PARAMETER!>foo<!>: C<X, Z, Y>) {
|
class D<X, Z, Y : X>(<!UNUSED_PARAMETER!>foo<!>: C<X, Z, Y>) {
|
||||||
fun test(a: C<Y, Y, Y>) {
|
fun test(a: C<Y, Y, Y>) {
|
||||||
val d: D<X, Y, Y> = <!TYPE_MISMATCH!>D(a)<!>
|
val d: D<X, Y, Y> = <!TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH!>D<!>(a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Vendored
+2
-2
@@ -17,8 +17,8 @@ fun test(out: Out<Int>, i: In<Int>, inv: A<Int>) {
|
|||||||
r checkType { _<Int>() }
|
r checkType { _<Int>() }
|
||||||
|
|
||||||
// T? <: Int => error
|
// T? <: Int => error
|
||||||
doIn(<!TYPE_MISMATCH!>i<!>)
|
<!TYPE_INFERENCE_INCORPORATION_ERROR!>doIn<!>(<!TYPE_MISMATCH!>i<!>)
|
||||||
|
|
||||||
// T? >: Int => error
|
// T? >: Int => error
|
||||||
doA(<!TYPE_MISMATCH!>inv<!>)
|
<!TYPE_INFERENCE_INCORPORATION_ERROR!>doA<!>(<!TYPE_MISMATCH!>inv<!>)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ import p.J.*
|
|||||||
|
|
||||||
class Foo<T>: Sub<T> {
|
class Foo<T>: Sub<T> {
|
||||||
fun foo(): Super<T> {
|
fun foo(): Super<T> {
|
||||||
return <!TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER!>Foo<!>()
|
return Foo()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.resolve.TypeResolver
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL
|
||||||
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.registerTypeVariables
|
||||||
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
import org.jetbrains.kotlin.resolve.lazy.JvmResolveUtil
|
||||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||||
import org.jetbrains.kotlin.test.JetLiteFixture
|
import org.jetbrains.kotlin.test.JetLiteFixture
|
||||||
|
|||||||
+4
-3
@@ -17,10 +17,10 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.inference
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPosition
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
public trait ConstraintSystem {
|
public trait ConstraintSystem {
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ public trait ConstraintSystem {
|
|||||||
*/
|
*/
|
||||||
public fun registerTypeVariables(
|
public fun registerTypeVariables(
|
||||||
typeVariables: Collection<TypeParameterDescriptor>,
|
typeVariables: Collection<TypeParameterDescriptor>,
|
||||||
typeVariableVariance: (TypeParameterDescriptor) -> Variance,
|
variance: (TypeParameterDescriptor) -> Variance,
|
||||||
|
mapToOriginal: (TypeParameterDescriptor) -> TypeParameterDescriptor,
|
||||||
external: Boolean = false
|
external: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+53
-29
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve.calls.inference
|
package org.jetbrains.kotlin.resolve.calls.inference
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||||
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.ConstraintSystemImpl.ConstraintKind.EQUAL
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl.ConstraintKind.EQUAL
|
||||||
@@ -28,6 +29,7 @@ import org.jetbrains.kotlin.resolve.calls.inference.TypeBounds.BoundKind.UPPER_B
|
|||||||
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.CompoundConstraintPosition
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.CompoundConstraintPosition
|
||||||
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.EXPECTED_TYPE_POSITION
|
||||||
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.equalsOrContains
|
import org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.equalsOrContains
|
||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
@@ -70,6 +72,12 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
|
|
||||||
private val initialConstraints = ArrayList<Constraint>()
|
private val initialConstraints = ArrayList<Constraint>()
|
||||||
|
|
||||||
|
private val originalToVariablesSubstitutor: TypeSubstitutor by lazy {
|
||||||
|
createTypeSubstitutor { originalToVariables[it] }
|
||||||
|
}
|
||||||
|
private val originalToVariables = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
|
||||||
|
private val variablesToOriginal = LinkedHashMap<TypeParameterDescriptor, TypeParameterDescriptor>()
|
||||||
|
|
||||||
private val constraintSystemStatus = object : ConstraintSystemStatus {
|
private val constraintSystemStatus = object : ConstraintSystemStatus {
|
||||||
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
|
// for debug ConstraintsUtil.getDebugMessageForStatus might be used
|
||||||
|
|
||||||
@@ -101,7 +109,8 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
|
|
||||||
private fun getParameterToInferredValueMap(
|
private fun getParameterToInferredValueMap(
|
||||||
typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>,
|
typeParameterBounds: Map<TypeParameterDescriptor, TypeBoundsImpl>,
|
||||||
getDefaultTypeProjection: (TypeParameterDescriptor) -> TypeProjection
|
getDefaultTypeProjection: (TypeParameterDescriptor) -> TypeProjection,
|
||||||
|
substituteOriginal: Boolean
|
||||||
): Map<TypeParameterDescriptor, TypeProjection> {
|
): Map<TypeParameterDescriptor, TypeProjection> {
|
||||||
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
|
val substitutionContext = HashMap<TypeParameterDescriptor, TypeProjection>()
|
||||||
for ((typeParameter, typeBounds) in typeParameterBounds) {
|
for ((typeParameter, typeBounds) in typeParameterBounds) {
|
||||||
@@ -113,34 +122,34 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
else {
|
else {
|
||||||
typeProjection = getDefaultTypeProjection(typeParameter)
|
typeProjection = getDefaultTypeProjection(typeParameter)
|
||||||
}
|
}
|
||||||
substitutionContext.put(typeParameter, typeProjection)
|
substitutionContext.put(if (substituteOriginal) variablesToOriginal[typeParameter]!! else typeParameter, typeProjection)
|
||||||
}
|
}
|
||||||
return substitutionContext
|
return substitutionContext
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replaceUninferredBy(getDefaultValue: (TypeParameterDescriptor) -> TypeProjection): TypeSubstitutor {
|
private fun replaceUninferredBy(
|
||||||
return TypeUtils.makeSubstitutorForTypeParametersMap(getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue))
|
getDefaultValue: (TypeParameterDescriptor) -> TypeProjection,
|
||||||
}
|
substituteOriginal: Boolean
|
||||||
|
): TypeSubstitutor {
|
||||||
private fun replaceUninferredBy(defaultValue: JetType): TypeSubstitutor {
|
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
|
||||||
return replaceUninferredBy { TypeProjectionImpl(defaultValue) }
|
return TypeUtils.makeSubstitutorForTypeParametersMap(parameterToInferredValueMap)
|
||||||
}
|
|
||||||
|
|
||||||
private fun replaceUninferredBySpecialErrorType(): TypeSubstitutor {
|
|
||||||
return replaceUninferredBy { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getStatus(): ConstraintSystemStatus = constraintSystemStatus
|
override fun getStatus(): ConstraintSystemStatus = constraintSystemStatus
|
||||||
|
|
||||||
override fun registerTypeVariables(
|
override fun registerTypeVariables(
|
||||||
typeVariables: Collection<TypeParameterDescriptor>,
|
typeVariables: Collection<TypeParameterDescriptor>,
|
||||||
typeVariableVariance: (TypeParameterDescriptor) -> Variance,
|
variance: (TypeParameterDescriptor) -> Variance,
|
||||||
|
mapToOriginal: (TypeParameterDescriptor) -> TypeParameterDescriptor,
|
||||||
external: Boolean
|
external: Boolean
|
||||||
) {
|
) {
|
||||||
if (external) externalTypeParameters.addAll(typeVariables)
|
if (external) externalTypeParameters.addAll(typeVariables)
|
||||||
|
|
||||||
for (typeVariable in typeVariables) {
|
for (typeVariable in typeVariables) {
|
||||||
allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable, typeVariableVariance(typeVariable)))
|
allTypeParameterBounds.put(typeVariable, TypeBoundsImpl(typeVariable, variance(typeVariable)))
|
||||||
|
val original = mapToOriginal(typeVariable)
|
||||||
|
originalToVariables[original] = typeVariable
|
||||||
|
variablesToOriginal[typeVariable] = original
|
||||||
}
|
}
|
||||||
for ((typeVariable, typeBounds) in allTypeParameterBounds) {
|
for ((typeVariable, typeBounds) in allTypeParameterBounds) {
|
||||||
for (declaredUpperBound in typeVariable.getUpperBounds()) {
|
for (declaredUpperBound in typeVariable.getUpperBounds()) {
|
||||||
@@ -160,11 +169,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables()
|
type -> type.getConstructor().getDeclarationDescriptor() in getAllTypeVariables()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JetType.getNestedTypeVariables(): List<TypeParameterDescriptor> {
|
fun JetType.getNestedTypeVariables(original: Boolean = false): List<TypeParameterDescriptor> {
|
||||||
return getNestedTypeArguments().map { typeProjection ->
|
return getNestedTypeArguments().map { typeProjection ->
|
||||||
typeProjection.getType().getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor
|
typeProjection.getType().getConstructor().getDeclarationDescriptor() as? TypeParameterDescriptor
|
||||||
|
}.filterNotNull().filter { if (original) it in originalToVariables.keySet() else it in getAllTypeVariables() }
|
||||||
}.filterNotNull().filter { it in getAllTypeVariables() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun copy(): ConstraintSystem = createNewConstraintSystemFromThis({ it }, { true })
|
public fun copy(): ConstraintSystem = createNewConstraintSystemFromThis({ it }, { true })
|
||||||
@@ -216,17 +224,21 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
val newSuperType = typeSubstitutor.substitute(it.superType, Variance.INVARIANT)
|
val newSuperType = typeSubstitutor.substitute(it.superType, Variance.INVARIANT)
|
||||||
if (newSubType != null && newSuperType != null) Constraint(it.kind, newSubType, newSuperType, it.position) else null
|
if (newSubType != null && newSuperType != null) Constraint(it.kind, newSubType, newSuperType, it.position) else null
|
||||||
})
|
})
|
||||||
|
newSystem.originalToVariables.putAll(originalToVariables)
|
||||||
|
newSystem.variablesToOriginal.putAll(variablesToOriginal)
|
||||||
return newSystem
|
return newSystem
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addSupertypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
|
override fun addSupertypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
|
||||||
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
|
if (constrainingType != null && TypeUtils.noExpectedType(constrainingType)) return
|
||||||
|
|
||||||
addConstraint(SUB_TYPE, subjectType, constrainingType, constraintPosition)
|
val newSubjectType = originalToVariablesSubstitutor.substitute(subjectType, Variance.INVARIANT)
|
||||||
|
addConstraint(SUB_TYPE, newSubjectType, constrainingType, constraintPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun addSubtypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
|
override fun addSubtypeConstraint(constrainingType: JetType?, subjectType: JetType, constraintPosition: ConstraintPosition) {
|
||||||
addConstraint(SUB_TYPE, constrainingType, subjectType, constraintPosition)
|
val newSubjectType = originalToVariablesSubstitutor.substitute(subjectType, Variance.INVARIANT)
|
||||||
|
addConstraint(SUB_TYPE, constrainingType, newSubjectType, constraintPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addConstraint(constraintKind: ConstraintKind, subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition) {
|
fun addConstraint(constraintKind: ConstraintKind, subType: JetType?, superType: JetType?, constraintPosition: ConstraintPosition) {
|
||||||
@@ -429,24 +441,23 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
addBound(typeVariable, capturedType, EXACT_BOUND, constraintPosition)
|
addBound(typeVariable, capturedType, EXACT_BOUND, constraintPosition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getTypeVariables() = typeParameterBounds.keySet()
|
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 {
|
override fun getTypeBounds(typeVariable: TypeParameterDescriptor): TypeBoundsImpl {
|
||||||
|
val variableForOriginal = originalToVariables[typeVariable]
|
||||||
|
if (variableForOriginal != null && variableForOriginal != typeVariable) {
|
||||||
|
return getTypeBounds(variableForOriginal)
|
||||||
|
}
|
||||||
if (!isMyTypeVariable(typeVariable)) {
|
if (!isMyTypeVariable(typeVariable)) {
|
||||||
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
||||||
}
|
}
|
||||||
return allTypeParameterBounds[typeVariable]!!
|
return allTypeParameterBounds[typeVariable]!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTypeBounds(parameterType: JetType): TypeBoundsImpl {
|
|
||||||
assert (isMyTypeVariable(parameterType)) { "Type is not a type variable for constraint system: $parameterType" }
|
|
||||||
return getTypeBounds(getMyTypeVariable(parameterType)!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun isMyTypeVariable(typeVariable: TypeParameterDescriptor) = allTypeParameterBounds.contains(typeVariable)
|
fun isMyTypeVariable(typeVariable: TypeParameterDescriptor) = allTypeParameterBounds.contains(typeVariable)
|
||||||
|
|
||||||
fun isMyTypeVariable(type: JetType): Boolean = getMyTypeVariable(type) != null
|
fun isMyTypeVariable(type: JetType): Boolean = getMyTypeVariable(type) != null
|
||||||
@@ -456,9 +467,14 @@ 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() = replaceUninferredBySpecialErrorType().setApproximateCapturedTypes()
|
override fun getResultingSubstitutor() =
|
||||||
|
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
||||||
|
|
||||||
override fun getCurrentSubstitutor() = replaceUninferredBy(TypeUtils.DONT_CARE).setApproximateCapturedTypes()
|
override fun getCurrentSubstitutor() =
|
||||||
|
getSubstitutor(substituteOriginal = true) { TypeProjectionImpl(TypeUtils.DONT_CARE) }
|
||||||
|
|
||||||
|
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeParameterDescriptor) -> TypeProjection) =
|
||||||
|
replaceUninferredBy(getDefaultValue, substituteOriginal).setApproximateCapturedTypes()
|
||||||
|
|
||||||
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: JetType, superType: JetType, position: ConstraintPosition) {
|
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: JetType, superType: JetType, position: ConstraintPosition) {
|
||||||
if (position is CompoundConstraintPosition) return
|
if (position is CompoundConstraintPosition) return
|
||||||
@@ -467,7 +483,8 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
|
|
||||||
private fun satisfyInitialConstraints(): Boolean {
|
private fun satisfyInitialConstraints(): Boolean {
|
||||||
fun JetType.substituteAndMakeNotNullable(): JetType? {
|
fun JetType.substituteAndMakeNotNullable(): JetType? {
|
||||||
val result = getResultingSubstitutor().substitute(this, Variance.INVARIANT) ?: return null
|
val substitutor = getSubstitutor(substituteOriginal = false) { TypeProjectionImpl(ErrorUtils.createUninferredParameterType(it)) }
|
||||||
|
val result = substitutor.substitute(this, Variance.INVARIANT) ?: return null
|
||||||
return TypeUtils.makeNotNullable(result)
|
return TypeUtils.makeNotNullable(result)
|
||||||
}
|
}
|
||||||
return initialConstraints.all {
|
return initialConstraints.all {
|
||||||
@@ -538,5 +555,12 @@ private class SubstitutionWithCapturedTypeApproximation(val substitution: TypeSu
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun ConstraintSystemImpl.registerTypeVariables(typeVariables: Map<TypeParameterDescriptor, Variance>) {
|
public fun ConstraintSystemImpl.registerTypeVariables(typeVariables: Map<TypeParameterDescriptor, Variance>) {
|
||||||
registerTypeVariables(typeVariables.keySet(), { typeVariables[it]!! })
|
registerTypeVariables(typeVariables.keySet(), { typeVariables[it]!! }, { it })
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun ConstraintSystemImpl.registerTypeVariables(
|
||||||
|
typeVariables: Collection<TypeParameterDescriptor>,
|
||||||
|
variance: (TypeParameterDescriptor) -> Variance
|
||||||
|
) {
|
||||||
|
registerTypeVariables(typeVariables, variance, { it })
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
|
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl
|
||||||
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.registerTypeVariables
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|||||||
Reference in New Issue
Block a user