package solve

import (
	
	
	
	
	
	

	
	
	
)

// 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 {
		return cmp.Or(diag.CmpPos(.pos, .pos), cmp.Compare(.idx, .idx))
	})
	 := make([]*types.TypeParam, len())
	for ,  := range  {
		[] = .tp
	}
	return 
}