@@ -35,6 +35,7 @@ import (
3535// Exactly one of the fields will be set.
3636type providerSetSrc struct {
3737 Provider * Provider
38+ AutoBinding * AutoBinding
3839 Binding * IfaceBinding
3940 Value * Value
4041 Import * ProviderSet
@@ -57,6 +58,8 @@ func (p *providerSetSrc) description(fset *token.FileSet, typ types.Type) string
5758 kind = "struct provider"
5859 }
5960 return fmt .Sprintf ("%s %s(%s)" , kind , quoted (p .Provider .Name ), fset .Position (p .Provider .Pos ))
61+ case p .AutoBinding != nil :
62+ return fmt .Sprintf ("wire.AutoBind (%s)" , fset .Position (p .AutoBinding .Pos ))
6063 case p .Binding != nil :
6164 return fmt .Sprintf ("autowire.Bind (%s)" , fset .Position (p .Binding .Pos ))
6265 case p .Value != nil :
@@ -98,12 +101,13 @@ type ProviderSet struct {
98101 // variable.
99102 VarName string
100103
101- Providers []* Provider
102- Bindings []* IfaceBinding
103- Values []* Value
104- Fields []* Field
105- Imports []* ProviderSet
106- // InjectorArgs is only filled in for autowire.Build.
104+ Providers []* Provider
105+ Bindings []* IfaceBinding
106+ AutoBindings []* AutoBinding
107+ Values []* Value
108+ Fields []* Field
109+ Imports []* ProviderSet
110+ // InjectorArgs is only filled in for wire.Build.
107111 InjectorArgs * InjectorArgs
108112
109113 // providerMap maps from provided type to a *ProvidedType.
@@ -125,6 +129,22 @@ func (set *ProviderSet) Outputs() []types.Type {
125129func (set * ProviderSet ) For (t types.Type ) ProvidedType {
126130 pt := set .providerMap .At (t )
127131 if pt == nil {
132+ // if t is an interface, we may have an AutoBinding that implements it.
133+ iface , ok := t .Underlying ().(* types.Interface )
134+ if ! ok {
135+ return ProvidedType {}
136+ }
137+
138+ for _ , ab := range set .AutoBindings {
139+ if types .Implements (ab .Concrete , iface ) {
140+ // cache for later
141+ pt := & ProvidedType {t : ab .Concrete , ab : ab }
142+ set .providerMap .Set (t , pt )
143+ set .srcMap .Set (t , & providerSetSrc {AutoBinding : ab })
144+ return * pt
145+ }
146+ }
147+
128148 return ProvidedType {}
129149 }
130150 return * pt .(* ProvidedType )
@@ -179,6 +199,17 @@ type Provider struct {
179199 HasErr bool
180200}
181201
202+ // AutoBinding records the signature of a provider eligible for auto-binding
203+ // to interfaces it implements. A provider is a single Go object, either a
204+ // function or a named type.
205+ type AutoBinding struct {
206+ // Concrete is always a type that implements N number of interfaces.
207+ Concrete types.Type
208+
209+ // Pos is the position where the binding was declared.
210+ Pos token.Pos
211+ }
212+
182213// ProviderInput describes an incoming edge in the provider graph.
183214type ProviderInput struct {
184215 Type types.Type
@@ -520,7 +551,7 @@ func (oc *objectCache) varDecl(obj *types.Var) *ast.ValueSpec {
520551}
521552
522553// processExpr converts an expression into a Wire structure. It may return a
523- // *Provider, an *IfaceBinding, a *ProviderSet, a *Value or a []*Field.
554+ // *Provider, an *AutoBinding, an * IfaceBinding, a *ProviderSet, a *Value or a []*Field.
524555func (oc * objectCache ) processExpr (info * types.Info , pkgPath string , expr ast.Expr , varName string ) (interface {}, []error ) {
525556 exprPos := oc .fset .Position (expr .Pos ())
526557 expr = astutil .Unparen (expr )
@@ -546,6 +577,12 @@ func (oc *objectCache) processExpr(info *types.Info, pkgPath string, expr ast.Ex
546577 case "NewSet" :
547578 pset , errs := oc .processNewSet (info , pkgPath , call , nil , varName )
548579 return pset , notePositionAll (exprPos , errs )
580+ case "AutoBind" :
581+ abs , err := processAutoBind (oc .fset , info , call )
582+ if err != nil {
583+ return nil , []error {notePosition (exprPos , err )}
584+ }
585+ return abs , nil
549586 case "Bind" :
550587 b , err := processBind (oc .fset , info , call )
551588 if err != nil {
@@ -607,6 +644,8 @@ func (oc *objectCache) processNewSet(info *types.Info, pkgPath string, call *ast
607644 continue
608645 }
609646 switch item := item .(type ) {
647+ case * AutoBinding :
648+ pset .AutoBindings = append (pset .AutoBindings , item )
610649 case * Provider :
611650 pset .Providers = append (pset .Providers , item )
612651 case * ProviderSet :
@@ -880,6 +919,41 @@ func isPrevented(tag string) bool {
880919 return reflect .StructTag (tag ).Get ("autowire" ) == "-"
881920}
882921
922+ func processAutoBind (fset * token.FileSet , info * types.Info , call * ast.CallExpr ) (* AutoBinding , error ) {
923+ // Assumes that call.Fun is wire.AutoBind.
924+
925+ if len (call .Args ) != 1 {
926+ return nil , notePosition (fset .Position (call .Pos ()),
927+ errors .New ("call to AutoBind takes exactly one argument" ))
928+ }
929+ const firstArgReqFormat = "first argument to AutoBind must be a pointer to a type; found %s"
930+ typ := info .TypeOf (call .Args [0 ])
931+ ptr , ok := typ .(* types.Pointer )
932+ if ! ok {
933+ return nil , notePosition (fset .Position (call .Pos ()),
934+ fmt .Errorf (firstArgReqFormat , types .TypeString (typ , nil )))
935+ }
936+
937+ switch ptr .Elem ().Underlying ().(type ) {
938+ case * types.Named ,
939+ * types.Struct ,
940+ * types.Basic :
941+ // good!
942+
943+ default :
944+ return nil , notePosition (fset .Position (call .Pos ()),
945+ fmt .Errorf (firstArgReqFormat , types .TypeString (ptr , nil )))
946+ }
947+
948+ typeExpr := call .Args [0 ].(* ast.CallExpr )
949+ typeName := qualifiedIdentObject (info , typeExpr .Args [0 ]) // should be either an identifier or selector
950+ autoBinding := & AutoBinding {
951+ Concrete : ptr ,
952+ Pos : typeName .Pos (),
953+ }
954+ return autoBinding , nil
955+ }
956+
883957// processBind creates an interface binding from a autowire.Bind call.
884958func processBind (fset * token.FileSet , info * types.Info , call * ast.CallExpr ) (* IfaceBinding , error ) {
885959 // Assumes that call.Fun is autowire.Bind.
@@ -1122,7 +1196,6 @@ func findInjectorBuild(info *types.Info, fn *ast.FuncDecl) (*ast.CallExpr, error
11221196 default :
11231197 invalid = true
11241198 }
1125-
11261199 }
11271200 if wireBuildCall == nil {
11281201 return nil , nil
@@ -1157,16 +1230,17 @@ func isProviderSetType(t types.Type) bool {
11571230// none of the above, and returns true for IsNil.
11581231type ProvidedType struct {
11591232 // t is the provided concrete type.
1160- t types.Type
1161- p * Provider
1162- v * Value
1163- a * InjectorArg
1164- f * Field
1233+ t types.Type
1234+ p * Provider
1235+ ab * AutoBinding
1236+ v * Value
1237+ a * InjectorArg
1238+ f * Field
11651239}
11661240
11671241// IsNil reports whether pt is the zero value.
11681242func (pt ProvidedType ) IsNil () bool {
1169- return pt .p == nil && pt .v == nil && pt .a == nil && pt .f == nil
1243+ return pt .p == nil && pt .ab == nil && pt . v == nil && pt .a == nil && pt .f == nil
11701244}
11711245
11721246// Type returns the output type.
@@ -1185,6 +1259,11 @@ func (pt ProvidedType) IsProvider() bool {
11851259 return pt .p != nil
11861260}
11871261
1262+ // IsAutoBinding reports whether pt points to an AutoBinding.
1263+ func (pt ProvidedType ) IsAutoBinding () bool {
1264+ return pt .ab != nil
1265+ }
1266+
11881267// IsValue reports whether pt points to a Value.
11891268func (pt ProvidedType ) IsValue () bool {
11901269 return pt .v != nil
@@ -1209,6 +1288,15 @@ func (pt ProvidedType) Provider() *Provider {
12091288 return pt .p
12101289}
12111290
1291+ // AutoBinding returns pt as a AutoBinding pointer. It panics if pt does not point
1292+ // to a AutoBinding.
1293+ func (pt ProvidedType ) AutoBinding () * AutoBinding {
1294+ if pt .ab == nil {
1295+ panic ("ProvidedType does not hold an AutoBinding" )
1296+ }
1297+ return pt .ab
1298+ }
1299+
12121300// Value returns pt as a Value pointer. It panics if pt does not point
12131301// to a Value.
12141302func (pt ProvidedType ) Value () * Value {
0 commit comments