Don't generate constraint if a type variable was substituted twice
to prevent infinite recursion
This commit is contained in:
+26
@@ -0,0 +1,26 @@
|
|||||||
|
VARIABLES T P E
|
||||||
|
|
||||||
|
SUBTYPE T Producer<P>
|
||||||
|
SUBTYPE P Producer<E>
|
||||||
|
SUBTYPE E Producer<P>
|
||||||
|
|
||||||
|
type parameter bounds:
|
||||||
|
T <: Producer<P>*, <: Producer<Producer<E>>*, <: Producer<Producer<Producer<P>>>*
|
||||||
|
P <: Producer<E>*
|
||||||
|
E <: Producer<P>*
|
||||||
|
|
||||||
|
status:
|
||||||
|
-hasCannotCaptureTypesError: false
|
||||||
|
-hasConflictingConstraints: false
|
||||||
|
-hasContradiction: false
|
||||||
|
-hasErrorInConstrainingTypes: false
|
||||||
|
-hasTypeConstructorMismatch: false
|
||||||
|
-hasTypeInferenceIncorporationError: false
|
||||||
|
-hasUnknownParameters: true
|
||||||
|
-hasViolatedUpperBound: false
|
||||||
|
-isSuccessful: false
|
||||||
|
|
||||||
|
result:
|
||||||
|
T=???
|
||||||
|
P=???
|
||||||
|
E=???
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
VARIABLES T P E
|
||||||
|
|
||||||
|
SUBTYPE T Producer<P>
|
||||||
|
SUBTYPE P Producer<E>
|
||||||
|
SUBTYPE E Producer<P>
|
||||||
+6
@@ -441,6 +441,12 @@ public class ConstraintSystemTestGenerated extends AbstractConstraintSystemTest
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/constraintSystem/severalVariables/recursive"), Pattern.compile("^(.+)\\.constraints$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/constraintSystem/severalVariables/recursive"), Pattern.compile("^(.+)\\.constraints$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("implicitlyRecursive.constraints")
|
||||||
|
public void testImplicitlyRecursive() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/constraintSystem/severalVariables/recursive/implicitlyRecursive.constraints");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("mutuallyRecursive.constraints")
|
@TestMetadata("mutuallyRecursive.constraints")
|
||||||
public void testMutuallyRecursive() throws Exception {
|
public void testMutuallyRecursive() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.constraints");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.constraints");
|
||||||
|
|||||||
+3
-2
@@ -346,9 +346,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
|
|||||||
typeVariable: TypeParameterDescriptor,
|
typeVariable: TypeParameterDescriptor,
|
||||||
constrainingType: JetType,
|
constrainingType: JetType,
|
||||||
kind: TypeBounds.BoundKind,
|
kind: TypeBounds.BoundKind,
|
||||||
position: ConstraintPosition
|
position: ConstraintPosition,
|
||||||
|
derivedFrom: Set<TypeParameterDescriptor> = emptySet()
|
||||||
) {
|
) {
|
||||||
val bound = Bound(typeVariable, constrainingType, kind, position, constrainingType.isProper())
|
val bound = Bound(typeVariable, constrainingType, kind, position, constrainingType.isProper(), derivedFrom)
|
||||||
val typeBounds = getTypeBounds(typeVariable)
|
val typeBounds = getTypeBounds(typeVariable)
|
||||||
if (typeBounds.bounds.contains(bound)) return
|
if (typeBounds.bounds.contains(bound)) return
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,9 @@ public trait TypeBounds {
|
|||||||
public val constrainingType: JetType,
|
public val constrainingType: JetType,
|
||||||
public val kind: BoundKind,
|
public val kind: BoundKind,
|
||||||
public val position: ConstraintPosition,
|
public val position: ConstraintPosition,
|
||||||
public val isProper: Boolean = true
|
public val isProper: Boolean,
|
||||||
|
// to prevent infinite recursion in incorporation we store the variables that was substituted to derive this bound
|
||||||
|
public val derivedFrom: Set<TypeParameterDescriptor>
|
||||||
) {
|
) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
|
|||||||
@@ -194,7 +194,8 @@ fun Collection<Bound>.substitute(substituteTypeVariable: (TypeParameterDescripto
|
|||||||
it.constrainingType
|
it.constrainingType
|
||||||
}
|
}
|
||||||
substitutedType?.let { type ->
|
substitutedType?.let { type ->
|
||||||
Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper)
|
Bound(substituteTypeVariable(it.typeVariable) ?: it.typeVariable, type, it.kind, it.position, it.isProper,
|
||||||
|
it.derivedFrom.map { substituteTypeVariable(it) ?: it }.toSet())
|
||||||
}
|
}
|
||||||
}.filterNotNull()
|
}.filterNotNull()
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-2
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.types.*
|
|||||||
import org.jetbrains.kotlin.types.Variance.INVARIANT
|
import org.jetbrains.kotlin.types.Variance.INVARIANT
|
||||||
import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments
|
import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments
|
||||||
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
fun ConstraintSystemImpl.incorporateBound(newBound: Bound) {
|
fun ConstraintSystemImpl.incorporateBound(newBound: Bound) {
|
||||||
val typeVariable = newBound.typeVariable
|
val typeVariable = newBound.typeVariable
|
||||||
@@ -92,9 +93,14 @@ private fun ConstraintSystemImpl.generateNewBound(bound: Bound, substitution: Bo
|
|||||||
fun addNewBound(newConstrainingType: JetType, newBoundKind: BoundKind) {
|
fun addNewBound(newConstrainingType: JetType, newBoundKind: BoundKind) {
|
||||||
// We don't generate new recursive constraints
|
// We don't generate new recursive constraints
|
||||||
val nestedTypeVariables = newConstrainingType.getNestedTypeVariables()
|
val nestedTypeVariables = newConstrainingType.getNestedTypeVariables()
|
||||||
if (nestedTypeVariables.contains(bound.typeVariable) || nestedTypeVariables.contains(substitution.typeVariable)) return
|
if (nestedTypeVariables.contains(bound.typeVariable)) return
|
||||||
|
|
||||||
addBound(bound.typeVariable, newConstrainingType, newBoundKind, position)
|
// We don't generate constraint if a type variable was substituted twice
|
||||||
|
val derivedFrom = HashSet(bound.derivedFrom + substitution.derivedFrom)
|
||||||
|
if (derivedFrom.contains(substitution.typeVariable)) return
|
||||||
|
|
||||||
|
derivedFrom.add(substitution.typeVariable)
|
||||||
|
addBound(bound.typeVariable, newConstrainingType, newBoundKind, position, derivedFrom)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (substitution.kind == EXACT_BOUND) {
|
if (substitution.kind == EXACT_BOUND) {
|
||||||
|
|||||||
Reference in New Issue
Block a user