package solveimport ()// liftAll lifts every type parameter of an anchor template, returning the fresh// parameters as type arguments.func ( *solver) ( *discover.Provider) []types.Type { := make([]types.Type, .Tparams.Len()) := make([]int, .Tparams.Len())for := range .Tparams.Len() { [] = .liftOne(.Tparams.At(), ) [] = } .setLiftedConstraints(, , )return}// setLiftedConstraints rewrites the constraint of each freshly lifted parameter// (the indices in fresh) so that references to the template's other parameters// point at their resolved targets: concrete types for pinned parameters, the// co-lifted fresh parameters for the rest. The original template parameters are// not in scope in the generated header, so an inter-parameter constraint such as// U interface{ ~[]T } must travel as ~[]<pin or lifted T>, not the verbatim T.// Leaving it verbatim renders a dangling identifier (uncompilable) and makes// types.Instantiate's validation reject the lift.func ( *solver) ( *discover.Provider, []types.Type, []int) { := make(map[*types.TypeParam]types.Type, .Tparams.Len())for := range .Tparams.Len() { [.Tparams.At()] = [] }for , := range { := [].(*types.TypeParam)if := .Tparams.At().Constraint(); != nil { .SetConstraint(gotypes.Subst(.ctxt, , )) } }}// liftOne creates a fresh injector type parameter standing in for an unpinned// template parameter. Its name is chosen to avoid the destination's identifiers// and the predeclared names the body emits, so it never shadows anything the// generated body references unqualified.func ( *solver) ( *types.TypeParam, *discover.Provider) *types.TypeParam { := .freshLiftedName(.Obj().Name())// Globally-unique live lifted names are the whole basis of the solver's // determinism: they are the only source of a CmpType weak-order tie (two // lifted parameters compare equal iff their names match; see gotypes.CmpType), // and a stable sort over the map-ordered demand/input/output slices would // otherwise be load-order-dependent. freshLiftedName guarantees uniqueness, so // a duplicate here means that guarantee (or rollbackLifts' name release) // regressed; fail loud at the source rather than emit nondeterministic code.if .liftedNames[] {panic(fmt.Sprintf("plumb: lifted name %q reused; determinism relies on unique live lifted names", )) } := types.NewTypeName(token.NoPos, nil, , nil) := types.NewTypeParam(, nil) .SetConstraint(.Constraint()) .liftedNames[] = true .liftedMeta = append(.liftedMeta, liftedParam{tp: , pos: .Pos, idx: .Index()})return}// rollbackLifts undoes the speculative lifts appended since mark: it both// truncates liftedMeta and releases the names those lifts reserved in liftedNames.// Releasing the names is what lets a later successful lift reuse a name a failed// attempt had taken (e.g. T rather than T2); liftedMeta and liftedNames must be// rolled back together or the two go out of sync.func ( *solver) ( int) {for , := range .liftedMeta[:] {delete(.liftedNames, .tp.Obj().Name()) } .liftedMeta = .liftedMeta[:]}// freshLiftedName returns a valid identifier derived from base that collides// with nothing the body references unqualified.func ( *solver) ( string) string {if == "" || == "_" { = "T" } := for := 2; .avoid[] || .liftedNames[]; ++ { = + strconv.Itoa() }return}// orderedLifted returns the lifted parameters in deterministic header order:// by the source position of their origin template, then parameter index.func ( *solver) () []*types.TypeParam { := slices.SortedStableFunc(slices.Values(.liftedMeta), func(, liftedParam) int {returncmp.Or(diag.CmpPos(.pos, .pos), cmp.Compare(.idx, .idx)) }) := make([]*types.TypeParam, len())for , := range { [] = .tp }return}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)