@@ -708,6 +708,7 @@ type Checker struct {
708708 circularityMark int // Length of discard log when the cycle in progress was detected
709709 innerCycles []innerCycle // Cycles detected inside the one in progress; see extendCircularity
710710 flowDepthFailures map[FlowLoopKey]int // Largest depth budget known to be too small for a flow walk from a node; see getTypeAtFlowNode
711+ observedHead int32 // 1 + index in resolutions of the lowest head of a cycle observed by the innermost type resolution in progress, or 0
711712 cycleParticipants []TypeResolution // Computations that observed a cycle in progress
712713 effectsMarkDepth int // 1 + resolution index of the innermost effects mark that may be discarded, or 0
713714 varianceStack []VarianceStackEntry
@@ -20335,9 +20336,20 @@ type cycleYield struct {
2033520336 savedResolutionStart int
2033620337 savedVisibleStart int
2033720338 savedDepths [3]depthLimit
20339+ savedReverseMapped reverseMappedState
20340+ savedContextual []ContextualInfo
20341+ savedInference []InferenceContextInfo
20342+ floor int
2033820343 shadowed []shadowedResolving
2033920344}
2034020345
20346+ type reverseMappedState struct {
20347+ sourceStack []*Type
20348+ targetStack []*Type
20349+ expandingFlags ExpandingFlags
20350+ start int32
20351+ }
20352+
2034120353type shadowedResolving struct {
2034220354 key memoKey
2034320355 index int32
@@ -20521,7 +20533,15 @@ func (c *Checker) beginCycleYield(target TypeSystemEntity, propertyName TypeSyst
2052120533 savedResolutionStart: c.resolutionStart,
2052220534 savedVisibleStart: c.visibleStart,
2052320535 savedDepths: [3]depthLimit{c.serializationLevel, c.inlineLevel, c.conditionalConstraintDepth},
20536+ savedReverseMapped: reverseMappedState{c.reverseMappedSourceStack, c.reverseMappedTargetStack, c.reverseExpandingFlags, c.reverseMappedStart},
20537+ savedContextual: c.contextualInfos,
20538+ savedInference: c.inferenceContextInfos,
20539+ floor: floor,
2052420540 })
20541+ // The contexts the hidden resolutions entered are hidden too, so that the
20542+ // recomputation is from scratch.
20543+ c.reverseMappedSourceStack, c.reverseMappedTargetStack, c.reverseExpandingFlags, c.reverseMappedStart = nil, nil, 0, 0
20544+ c.contextualInfos, c.inferenceContextInfos = nil, nil
2052520545 c.resolutionStart = n
2052620546 c.visibleStart = n
2052720547 c.serializationLevel, c.inlineLevel, c.conditionalConstraintDepth = depthLimit{}, depthLimit{}, depthLimit{}
@@ -20532,6 +20552,9 @@ func (c *Checker) endCycleYield() {
2053220552 c.resolutionStart = y.savedResolutionStart
2053320553 c.visibleStart = y.savedVisibleStart
2053420554 c.serializationLevel, c.inlineLevel, c.conditionalConstraintDepth = y.savedDepths[0], y.savedDepths[1], y.savedDepths[2]
20555+ r := y.savedReverseMapped
20556+ c.reverseMappedSourceStack, c.reverseMappedTargetStack, c.reverseExpandingFlags, c.reverseMappedStart = r.sourceStack, r.targetStack, r.expandingFlags, r.start
20557+ c.contextualInfos, c.inferenceContextInfos = y.savedContextual, y.savedInference
2053520558 for _, sh := range y.shadowed {
2053620559 c.resolving.set(sh.key, sh.index)
2053720560 }
@@ -20797,6 +20820,42 @@ func (c *Checker) markTypeResolutionCircular(start int) {
2079720820 c.markCircular(start)
2079820821}
2079920822
20823+ // keepsResultInCycle reports whether the type resolution at index n, which
20824+ // observed the cycles whose lowest head is observed (see Checker.observedHead),
20825+ // computes what it computes first from scratch although a cycle is in
20826+ // progress, so that its result is kept as a participant of the cycle:
20827+ // - The resolution re-entered a hidden resolution of itself, which a
20828+ // computation from scratch of the outer one always does, and what it
20829+ // observed in progress was all entered by the outer one, so its result is
20830+ // what the outer one computes first from scratch.
20831+ // - The resolution is the one a cycle yield computes again from scratch,
20832+ // with everything below it hidden, and it observed nothing hidden.
20833+ // - The resolution is inside the outermost measurement of variances, which
20834+ // hides what is below it and is measured from the canonical entry of its
20835+ // circularity, so what it computes is the same whatever led to it, and it
20836+ // only observed its incomplete variances. Computing it first from scratch
20837+ // reaches the measurement and computes it again inside, the same way.
20838+ func (c *Checker) keepsResultInCycle(n int, f *resolution, observed int32) bool {
20839+ r := &f.typeResolution
20840+ if r.outerSelf != 0 && observed != 0 && observed >= r.outerSelf && int(observed) <= n {
20841+ return true
20842+ }
20843+ if len(c.cycleYields) != 0 {
20844+ y := &c.cycleYields[len(c.cycleYields)-1]
20845+ if n >= y.floor && int(f.prevTypeResolution) <= y.floor && (observed == 0 || int(observed) > y.floor) {
20846+ return true
20847+ }
20848+ }
20849+ return c.observedOnlyOutermostMeasurement(n)
20850+ }
20851+
20852+ func minObservedHead(a int32, b int32) int32 {
20853+ if a == 0 || b != 0 && b < a {
20854+ return b
20855+ }
20856+ return a
20857+ }
20858+
2080020859// observedOnlyOutermostMeasurement reports whether the cycle in progress is
2080120860// the one headed by the outermost measurement of variances, which the
2080220861// resolution at index n is inside, and no other.
@@ -20855,21 +20914,9 @@ func (c *Checker) popTypeResolution() bool {
2085520914 debug.Assert(c.typeResolutionTop == n+1, "resolutions left above a type resolution")
2085620915 f := &c.resolutions[n]
2085720916 result := f.typeResolution.result
20858- if r := &f.typeResolution; r.outerSelf != 0 && result && c.circularityStart != 0 && c.circularityStart <= n && c.circularityStart >= int(r.outerSelf) && !r.participant {
20859- // The resolution re-entered a hidden resolution of itself, which a
20860- // computation from scratch of the outer one always does, and what it
20861- // observed in progress was all entered by the outer one, so its result
20862- // is what the outer one computes first from scratch: the outer one
20863- // keeps it, as must the cycle.
20864- r.participant = true
20865- c.cycleParticipants = append(c.cycleParticipants, *r)
20866- } else if r := &f.typeResolution; result && !r.participant && c.observedOnlyOutermostMeasurement(n) {
20867- // The outermost measurement of variances hides what is below it and
20868- // is measured from the canonical entry of its circularity, so what
20869- // it computes is the same whatever led to it. This resolution only
20870- // observed its incomplete variances, so its result is what it
20871- // computes first from scratch too, which reaches the measurement and
20872- // computes it again inside, as main keeps the first result set.
20917+ observed := c.observedHead
20918+ c.observedHead = minObservedHead(f.prevObservedHead, observed)
20919+ if r := &f.typeResolution; result && !r.participant && c.circularityStart != 0 && c.keepsResultInCycle(n, f, observed) {
2087320920 r.participant = true
2087420921 c.cycleParticipants = append(c.cycleParticipants, *r)
2087520922 }
@@ -20901,6 +20948,8 @@ func (c *Checker) beginTypeResolution(target TypeSystemEntity, propertyName Type
2090120948 f.prevMemo = int32(c.memoTop)
2090220949 f.isTypeResolution = true
2090320950 f.prevTypeResolution = int32(c.typeResolutionTop)
20951+ f.prevObservedHead = c.observedHead
20952+ c.observedHead = 0
2090420953 f.typeResolution.target = target
2090520954 f.typeResolution.propertyName = propertyName
2090620955 f.typeResolution.result = true
0 commit comments