package solve
import (
)
type ResultKind int
const (
ResultKindValue ResultKind = iota
ResultKindCleanup
ResultKindError
)
type ResultSlot struct {
Kind ResultKind
Typ types.Type
Failable bool
}
type InputSlot struct {
typ types.Type
Name string
flexRecv bool
flexBase types.Type
}
type Instance struct {
Prov *discover.Provider
Targs []types.Type
Inputs []InputSlot
Results []ResultSlot
pos token.Position
}
func ( *Instance) () []types.Type {
var []types.Type
for , := range .Results {
if .Kind == ResultKindValue {
= append(, .Typ)
}
}
return
}
func ( *Instance) () []types.Type {
var []types.Type
for , := range .Inputs {
= append(, .typ)
}
return
}
func ( *discover.Provider, *types.Context, []types.Type) ( *Instance, *diag.Error, error) {
= &Instance{Prov: , Targs: , pos: .Pos}
switch .Kind {
case discover.KindFunc:
, := instSignature(, .Fn.Type().(*types.Signature), )
if != nil {
return nil, nil,
}
classifyParams(, , 0)
if := classifyResults(, , ); != nil {
return nil, , nil
}
case discover.KindMethod:
, , := methodSignature(, , )
if != nil {
return nil, nil,
}
.Inputs = append(.Inputs, InputSlot{typ: })
classifyParams(, , 0)
if := classifyResults(, , ); != nil {
return nil, , nil
}
case discover.KindSymbol:
.Results = []ResultSlot{{Kind: ResultKindValue, Typ: .Sym.Type()}}
case discover.KindConvert:
.Inputs = []InputSlot{{typ: .ConvertFrom}}
.Results = []ResultSlot{{Kind: ResultKindValue, Typ: .ConvertTo}}
case discover.KindField:
, , := fieldTypes(, , )
if != nil {
return nil, nil,
}
.Inputs = []InputSlot{{flexRecv: true, flexBase: , typ: }}
.Results = []ResultSlot{{Kind: ResultKindValue, Typ: }}
case discover.KindStruct:
, , := structFields(, , )
if != nil {
return nil, nil,
}
for , := range {
.Inputs = append(.Inputs, InputSlot{typ: .Type(), Name: .Name()})
}
.Results = []ResultSlot{{Kind: ResultKindValue, Typ: }}
default:
panic(fmt.Sprintf("plumb: unhandled provider kind %d", .Kind))
}
return , nil, nil
}
func ( *types.Context, *types.Signature, []types.Type) (*types.Signature, error) {
if len() == 0 {
return , nil
}
, := types.Instantiate(, , , true)
if != nil {
return nil,
}
return .(*types.Signature), nil
}
func ( *discover.Provider, *types.Context, []types.Type) ( types.Type, *types.Signature, error) {
:= .Owner
if len() > 0 {
, := types.Instantiate(, gotypes.GenericOrigin(.Owner), , true)
if != nil {
return nil, nil,
}
=
}
if , := .Underlying().(*types.Interface); {
for := range .Methods() {
if .Name() == .Fn.Name() {
return , .Type().(*types.Signature), nil
}
}
panic(fmt.Sprintf("plumb: method %s of provider %s vanished after instantiation", .Fn.Name(), .Name))
}
:= lookupMethod(.(*types.Named), .Fn.Name())
if == nil {
panic(fmt.Sprintf("plumb: method %s of provider %s vanished after instantiation", .Fn.Name(), .Name))
}
:= .Type().(*types.Signature)
return .Recv().Type(), , nil
}
func ( *discover.Provider, *types.Context, []types.Type) (types.Type, types.Type, error) {
:= .Owner
if len() > 0 {
, := types.Instantiate(, gotypes.GenericOrigin(.Owner), , true)
if != nil {
return nil, nil,
}
=
}
, := .Underlying().(*types.Struct)
if ! {
panic(fmt.Sprintf("plumb: receiver of field provider %s is not a struct after instantiation", .Name))
}
for := range .Fields() {
if .Name() == .Sym.Name() {
return .Type(), , nil
}
}
panic(fmt.Sprintf("plumb: field %s of provider %s vanished after instantiation", .Sym.Name(), .Name))
}
func ( *discover.Provider, *types.Context, []types.Type) ( types.Type, []*types.Var, error) {
= .Declared
if len() > 0 {
, := types.Instantiate(, gotypes.GenericOrigin(.Declared), , true)
if != nil {
return nil, nil,
}
=
}
, := .Underlying().(*types.Struct)
if ! {
panic(fmt.Sprintf("plumb: struct-type provider %s is not a struct after instantiation", .Name))
}
for := range .Fields() {
if .Exported() {
= append(, )
}
}
return , , nil
}
func ( *Instance, *types.Signature, int) {
:= .Params()
for := ; < .Len(); ++ {
:= .At()
.Inputs = append(.Inputs, InputSlot{typ: .Type(), Name: .Name()})
}
}
func ( *discover.Provider, *Instance, *types.Signature) *diag.Error {
:= .Results()
:= 0
for := range .Variables() {
:= .Type()
switch {
case gotypes.IsErrorType():
++
if > 1 {
return diag.Errorf(.Pos, diag.ErrMultipleErrors, "provider %s returns more than one error result; at most one is supported", .Name)
}
.Results = append(.Results, ResultSlot{Kind: ResultKindError})
case gotypes.IsBareCleanup():
.Results = append(.Results, ResultSlot{Kind: ResultKindCleanup, Failable: false})
case gotypes.IsFailableCleanup():
.Results = append(.Results, ResultSlot{Kind: ResultKindCleanup, Failable: true})
default:
.Results = append(.Results, ResultSlot{Kind: ResultKindValue, Typ: })
}
}
return nil
}
func ( *types.Named, string) *types.Func {
for := range .Methods() {
if .Name() == {
return
}
}
return nil
}