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.ValueArgument
|
||||
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.scopes.receivers.ExpressionReceiver
|
||||
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())
|
||||
}
|
||||
|
||||
private fun hasReturnTypeDependentOnUninferredParams(candidateDescriptor: CallableDescriptor, constraintSystem: ConstraintSystem): Boolean {
|
||||
val returnType = candidateDescriptor.getReturnType() ?: return false
|
||||
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
||||
val returnType = getReturnType() ?: return false
|
||||
|
||||
for (typeVariable in constraintSystem.getTypeVariables()) {
|
||||
val inferredValueForTypeVariable = constraintSystem.getTypeBounds(typeVariable).value
|
||||
if (inferredValueForTypeVariable == null) {
|
||||
if (TypeUtils.dependsOnTypeParameters(returnType, setOf(typeVariable))) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
val nestedTypeVariables = with (constraintSystem as ConstraintSystemImpl) {
|
||||
returnType.getNestedTypeVariables(original = true)
|
||||
}
|
||||
return false
|
||||
return nestedTypeVariables.any { constraintSystem.getTypeBounds(it).value == null }
|
||||
}
|
||||
|
||||
public fun hasInferredReturnType(candidateDescriptor: CallableDescriptor, constraintSystem: ConstraintSystem): Boolean {
|
||||
if (hasReturnTypeDependentOnUninferredParams(candidateDescriptor, constraintSystem)) return false
|
||||
public fun CallableDescriptor.hasInferredReturnType(constraintSystem: ConstraintSystem): Boolean {
|
||||
if (hasReturnTypeDependentOnUninferredParams(constraintSystem)) return false
|
||||
|
||||
// Expected type mismatch was reported before as 'TYPE_INFERENCE_EXPECTED_TYPE_MISMATCH'
|
||||
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.ConstraintSystemImpl
|
||||
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.VALUE_PARAMETER_POSITION
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus
|
||||
@@ -62,6 +63,7 @@ class GenericCandidateResolver(
|
||||
val candidate = candidateCall.getCandidateDescriptor()
|
||||
|
||||
val constraintSystem = ConstraintSystemImpl()
|
||||
candidateCall.setConstraintSystem(constraintSystem)
|
||||
|
||||
// If the call is recursive, e.g.
|
||||
// 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)
|
||||
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(candidateWithFreshVariables.getTypeParameters(), DONT_CARE)
|
||||
val substituteDontCare = makeConstantSubstitutor(candidate.getTypeParameters(), DONT_CARE)
|
||||
|
||||
// Value parameters
|
||||
for (entry in candidateCall.getValueArguments().entrySet()) {
|
||||
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()) {
|
||||
@@ -97,7 +98,7 @@ class GenericCandidateResolver(
|
||||
// Receiver
|
||||
// Error is already reported if something is missing
|
||||
val receiverArgument = candidateCall.getExtensionReceiver()
|
||||
val receiverParameter = candidateWithFreshVariables.getExtensionReceiverParameter()
|
||||
val receiverParameter = candidate.getExtensionReceiverParameter()
|
||||
if (receiverArgument.exists() && receiverParameter != null) {
|
||||
var receiverType: JetType? = if (context.candidateCall.isSafeCall())
|
||||
TypeUtils.makeNotNullable(receiverArgument.getType())
|
||||
@@ -109,11 +110,6 @@ class GenericCandidateResolver(
|
||||
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
|
||||
val hasContradiction = constraintSystem.getStatus().hasContradiction()
|
||||
if (!hasContradiction) {
|
||||
@@ -168,7 +164,7 @@ class GenericCandidateResolver(
|
||||
val returnType = candidateDescriptor.getReturnType() ?: return false
|
||||
|
||||
val nestedTypeVariables = with (argumentConstraintSystem) {
|
||||
returnType.getNestedTypeVariables()
|
||||
returnType.getNestedTypeVariables(original = true)
|
||||
}
|
||||
// we add an additional type variable only if no information is inferred for it.
|
||||
// otherwise we add currently inferred return type as before
|
||||
@@ -178,7 +174,7 @@ class GenericCandidateResolver(
|
||||
val conversion = candidateDescriptor.getTypeParameters().zip(candidateWithFreshVariables.getTypeParameters()).toMap()
|
||||
|
||||
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)
|
||||
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>) {
|
||||
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>() }
|
||||
|
||||
// T? <: Int => error
|
||||
doIn(<!TYPE_MISMATCH!>i<!>)
|
||||
<!TYPE_INFERENCE_INCORPORATION_ERROR!>doIn<!>(<!TYPE_MISMATCH!>i<!>)
|
||||
|
||||
// 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> {
|
||||
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.constraintPosition.ConstraintPositionKind.SPECIAL
|
||||
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.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.JetLiteFixture
|
||||
|
||||
Reference in New Issue
Block a user