Don't generate constraint if a type variable was substituted twice

to prevent infinite recursion
This commit is contained in:
Svetlana Isakova
2015-06-30 22:05:21 +03:00
parent 3b85ac90ba
commit 89e16ecbcc
7 changed files with 53 additions and 6 deletions
@@ -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=???
@@ -0,0 +1,5 @@
VARIABLES T P E
SUBTYPE T Producer<P>
SUBTYPE P Producer<E>
SUBTYPE E Producer<P>
@@ -441,6 +441,12 @@ public class ConstraintSystemTestGenerated extends AbstractConstraintSystemTest
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")
public void testMutuallyRecursive() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/constraintSystem/severalVariables/recursive/mutuallyRecursive.constraints");
@@ -346,9 +346,10 @@ public class ConstraintSystemImpl : ConstraintSystem {
typeVariable: TypeParameterDescriptor,
constrainingType: JetType,
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)
if (typeBounds.bounds.contains(bound)) return
@@ -49,7 +49,9 @@ public trait TypeBounds {
public val constrainingType: JetType,
public val kind: BoundKind,
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 {
if (this === other) return true
@@ -194,7 +194,8 @@ fun Collection<Bound>.substitute(substituteTypeVariable: (TypeParameterDescripto
it.constrainingType
}
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()
}
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.Variance.INVARIANT
import org.jetbrains.kotlin.types.typeUtil.getNestedTypeArguments
import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
import java.util.*
fun ConstraintSystemImpl.incorporateBound(newBound: Bound) {
val typeVariable = newBound.typeVariable
@@ -92,9 +93,14 @@ private fun ConstraintSystemImpl.generateNewBound(bound: Bound, substitution: Bo
fun addNewBound(newConstrainingType: JetType, newBoundKind: BoundKind) {
// We don't generate new recursive constraints
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) {