Source File
revision.go
Belonging Package
go.pact.im/x/plumb/internal/solve
package solveimport ()// This file holds the pinning-revision machinery layered on top of the base// demand fixpoint: the restart signal and bound, and the solver methods that// decide when to commit a merged pinning and replay. Its persist-across-restart// state (the commitments, refusedUnions, and pinnings fields) lives on the// solver in solve.go; the replay loop that consumes errRestart is in Set.// maxRestarts bounds pinning-revision restarts. Each restart commits a pinning// strictly larger than an existing instance's (or is preempted by a one-shot// refusal), so the bound is far above any real program.const maxRestarts = 100// errRestart signals, up through the fixpoint to Set, that a new pinning was// committed and resolution must replay from seed with it in force. It rides the// *diag.Error return channel but is a control-flow signal, not a diagnostic:// every layer compares it by identity (err == errRestart) and Set consumes it// before it can escape. It is a diag.Sentinel rather than a zero-value *Error so// that a stray format of an in-flight error prints the message instead of// nil-panicking.var errRestart = diag.Sentinel("plumb: internal: pinning-revision restart")// applyCommitment merges bind with the first committed pinning of p it is// compatible with, so a replay instantiates the union where the aborted run// would have split. A binding incompatible with every commitment (a distinct// instantiation of the same template) passes through unchanged.func ( *solver) ( *discover.Provider, map[*types.TypeParam]types.Type) map[*types.TypeParam]types.Type {for , := range .commitments[] {if compatibleBind(, ) {:= maps.Clone()maps.Copy(, )return}}return}// reviseOrSplit is the pinning-revision trigger: about to instantiate p at// bind, it looks for an existing instance of p whose pinning is compatible// with bind and would gain pins from it. When their union is viable and// mentions no lifted parameter, the union becomes a committed pinning and the// solve restarts to replay with it in force; otherwise the union is refused// once (recorded so it never re-triggers) and the split stands, the same// result the resolver reaches when no revision applies. Pinnings that conflict// on a shared slot are ordinary multi-instantiation and never trigger.func ( *solver) ( *discover.Provider, map[*types.TypeParam]types.Type) *diag.Error {for , := range .instances {if .Prov != {continue}:= .pinnings[]if == nil || !compatibleBind(, ) {continue}:= maps.Clone()maps.Copy(, )if len() == len() {continue // no new pins; instance dedup covers a subsumed binding}if .unionRefused(, ) {continue}:= slices.ContainsFunc(slices.Collect(maps.Values()), gotypes.ContainsTypeParam)if || !.bindInstantiates(, ) {// A lifted-parameter pin cannot survive the restart, and a// constraint-violating union cannot instantiate; either way the// fallback is the split, never a rejection..markUnionRefused(, )continue}// A union extending an existing commitment upgrades it in place:// applyCommitment must find the largest form, or every replay merges// with the smaller one and re-derives the extension forever, a// staircase that runs a convergent program into the restart cap. The// upgrade keeps a template's commitments pairwise incompatible, so the// first compatible commitment is the only one. A union the replay// re-derives without extending anything is already in force: commit// nothing, do not restart.for , := range .commitments[] {if !compatibleBind(, ) {continue}:= maps.Clone()maps.Copy(, )if len() == len() {return nil // union ⊆ c: already committed}.commitments[][] =return errRestart}.commitments[] = append(.commitments[], )return errRestart}return nil}func ( *solver) ( *discover.Provider, map[*types.TypeParam]types.Type) bool {:= .refusedUnions[]return != nil && .Contains(jointBindKey(, ))}func ( *solver) ( *discover.Provider, map[*types.TypeParam]types.Type) {:= .refusedUnions[]if == nil {= new(gotypes.Set[*types.Tuple]).refusedUnions[] =}.Add(jointBindKey(, ))}
The pages are generated with Golds v0.8.4. (GOOS=linux GOARCH=amd64)