package emit

import (
	
	
	

	
	
)

// renderInstance renders the value-producing expression for one instance: the
// provider call or reference, given a qualifier and the already-coerced argument
// expressions in input order. It is the single place provider kinds turn into Go
// source: solve decides the wiring, emit renders it.
func ( *solve.Instance,  *qualifier,  []string) string {
	 := .Prov
	switch .Kind {
	case discover.KindFunc:
		var  strings.Builder
		.WriteString(.objQual(.Fn))
		writeTypeArgs(&, , .Targs)
		.WriteByte('(')
		writeArgs(&, , .Fn.Type().(*types.Signature).Variadic())
		.WriteByte(')')
		return .String()
	case discover.KindMethod:
		// args[0] is the receiver expression. Variadic-ness is stable under
		// instantiation, so the origin method signature is authoritative.
		var  strings.Builder
		.WriteString(asReceiver([0]))
		.WriteByte('.')
		.WriteString(.Fn.Name())
		.WriteByte('(')
		writeArgs(&, [1:], .Fn.Type().(*types.Signature).Variadic())
		.WriteByte(')')
		return .String()
	case discover.KindSymbol:
		return .objQual(.Sym)
	case discover.KindConvert:
		 := .typeString(.ConvertTo)
		if convNeedsParens(.ConvertTo) {
			 = "(" +  + ")"
		}
		return fmt.Sprintf("%s(%s)", , [0])
	case discover.KindField:
		return asReceiver([0]) + "." + .Sym.Name()
	case discover.KindStruct:
		// The value result is the declared type, rendered as written; the inputs
		// carry the exported field names in composite-literal order.
		var  strings.Builder
		.WriteString(.typeString(.Results[0].Typ))
		.WriteByte('{')
		for ,  := range  {
			if  > 0 {
				.WriteString(", ")
			}
			.WriteString(.Inputs[].Name)
			.WriteString(": ")
			.WriteString()
		}
		.WriteByte('}')
		return .String()
	}
	panic(fmt.Sprintf("plumb: unhandled provider kind %d", .Kind))
}

// asReceiver parenthesizes a selector receiver when it is a value/pointer bridge.
// The bridge renders *T → T as "*x" and T → *T as "&x"; used bare as a
// receiver, "*x.M()" / "&x.M()" parse as "*(x.M())" / "&(x.M())", so they must
// become "(*x).M()" / "(&x).M()". A plain local name is already a primary
// expression and binds the selector correctly.
func ( string) string {
	if strings.HasPrefix(, "*") || strings.HasPrefix(, "&") {
		return "(" +  + ")"
	}
	return 
}

// convNeedsParens reports whether a conversion to t must parenthesize the type so
// that T(x) is not mis-parsed. T(x) goes wrong two ways: a leading operator (a
// pointer *T reads as a dereference, a receive-only <-chan T as a receive), and a
// rendered form ending in a result-less func (func()(x) reparses as func() (x),
// its result list swallowing the argument). The latter is reachable through slice,
// array, map-value, channel, and pointer tails. gofmt rescues neither: it leaves
// *T(x) as a dereference and breaks func()-tailed conversions rather than fixing
// them. (It does add parens around a top-level func *with* a result, e.g.
// func() int(x) → (func() int)(x), so that one case needs no help here.) Every
// other target (named/alias/interface/struct/basic types, and composites not
// ending in a bare func) renders unambiguously.
func ( types.Type) bool {
	switch u := .(type) {
	case *types.Pointer:
		return true
	case *types.Chan:
		if .Dir() == types.RecvOnly {
			return true
		}
	}
	return endsInResultlessFunc()
}

// endsInResultlessFunc reports whether t's rendered form ends in a result-less
// func type, reached directly or through a slice/array/map-value/channel/pointer
// element or a func's sole result. (A two-or-more result list renders in
// parentheses, which closes the type, so it does not end in a bare func.) A named
// or alias type renders as its name, so it is opaque and stops the recursion.
func ( types.Type) bool {
	switch u := .(type) {
	case *types.Signature:
		switch .Results().Len() {
		case 0:
			return true
		case 1:
			return (.Results().At(0).Type())
		default:
			return false
		}
	case *types.Slice:
		return (.Elem())
	case *types.Array:
		return (.Elem())
	case *types.Map:
		return (.Elem())
	case *types.Chan:
		return (.Elem())
	case *types.Pointer:
		return (.Elem())
	}
	return false
}

func ( *strings.Builder,  []string,  bool) {
	for ,  := range  {
		if  > 0 {
			.WriteString(", ")
		}
		.WriteString()
		if  &&  == len()-1 {
			.WriteString("...")
		}
	}
}

func ( *strings.Builder,  *qualifier,  []types.Type) {
	if len() == 0 {
		return
	}
	.WriteByte('[')
	for ,  := range  {
		if  > 0 {
			.WriteString(", ")
		}
		.WriteString(.typeString())
	}
	.WriteByte(']')
}