Skip to content

Commit

Permalink
fix!(container): fix issue with providing a module-scoped dependency …
Browse files Browse the repository at this point in the history
…from within a module (#11913)
  • Loading branch information
aaronc authored May 9, 2022
1 parent 10af6f9 commit 624539a
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 28 deletions.
23 changes: 22 additions & 1 deletion container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,19 +133,26 @@ func (c *container) getResolver(typ reflect.Type) (resolver, error) {
return c.resolvers[typ], nil
}

var stringType = reflect.TypeOf("")

func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (interface{}, error) {
providerGraphNode, err := c.locationGraphNode(provider.Location, key)
if err != nil {
return nil, err
}

hasModuleKeyParam := false
hasOwnModuleKeyParam := false
for _, in := range provider.Inputs {
typ := in.Type
if typ == moduleKeyType {
hasModuleKeyParam = true
}

if typ == ownModuleKeyType {
hasOwnModuleKeyParam = true
}

if isAutoGroupType(typ) {
return nil, fmt.Errorf("auto-group type %v can't be used as an input parameter", typ)
} else if isOnePerModuleType(typ) {
Expand All @@ -170,7 +177,7 @@ func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (inter
c.addGraphEdge(typeGraphNode, providerGraphNode)
}

if key != nil || !hasModuleKeyParam {
if !hasModuleKeyParam {
c.logf("Registering %s", provider.Location.String())
c.indentLogger()
defer c.dedentLogger()
Expand Down Expand Up @@ -227,6 +234,11 @@ func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (inter

return sp, nil
} else {
if hasOwnModuleKeyParam {
return nil, errors.Errorf("%T and %T must not be declared as dependencies on the same provided",
ModuleKey{}, OwnModuleKey{})
}

c.logf("Registering module-scoped provider: %s", provider.Location.String())
c.indentLogger()
defer c.dedentLogger()
Expand Down Expand Up @@ -314,6 +326,15 @@ func (c *container) resolve(in ProviderInput, moduleKey *moduleKey, caller Locat
return reflect.ValueOf(ModuleKey{moduleKey}), nil
}

if in.Type == ownModuleKeyType {
if moduleKey == nil {
return reflect.Value{}, errors.Errorf("trying to resolve %T for %s but not inside of any module's scope", moduleKey, caller)
}
c.logf("Providing OwnModuleKey %s", moduleKey.name)
markGraphNodeAsUsed(typeGraphNode)
return reflect.ValueOf(OwnModuleKey{moduleKey}), nil
}

vr, err := c.getResolver(in.Type)
if err != nil {
return reflect.Value{}, err
Expand Down
31 changes: 12 additions & 19 deletions container/container_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,13 @@ type KVStoreKey struct {
name string
}

type ModuleKey string

type MsgClientA struct {
key ModuleKey
key string
}

type KeeperA struct {
key KVStoreKey
key KVStoreKey
name string
}

type KeeperB struct {
Expand All @@ -46,18 +45,14 @@ func ProvideKVStoreKey(moduleKey container.ModuleKey) KVStoreKey {
return KVStoreKey{name: moduleKey.Name()}
}

func ProvideModuleKey(moduleKey container.ModuleKey) (ModuleKey, error) {
return ModuleKey(moduleKey.Name()), nil
}

func ProvideMsgClientA(_ container.ModuleKey, key ModuleKey) MsgClientA {
return MsgClientA{key}
func ProvideMsgClientA(key container.ModuleKey) MsgClientA {
return MsgClientA{key.Name()}
}

type ModuleA struct{}

func (ModuleA) Provide(key KVStoreKey) (KeeperA, Handler, Command) {
return KeeperA{key}, Handler{}, Command{}
func (ModuleA) Provide(key KVStoreKey, moduleKey container.OwnModuleKey) (KeeperA, Handler, Command) {
return KeeperA{key: key, name: container.ModuleKey(moduleKey).Name()}, Handler{}, Command{}
}

type ModuleB struct{}
Expand All @@ -76,7 +71,7 @@ type BProvides struct {
Commands []Command
}

func (ModuleB) Provide(dependencies BDependencies, _ container.ModuleKey) (BProvides, Handler, error) {
func (ModuleB) Provide(dependencies BDependencies) (BProvides, Handler, error) {
return BProvides{
KeeperB: KeeperB{
key: dependencies.Key,
Expand All @@ -95,7 +90,8 @@ func TestScenario(t *testing.T) {
require.Equal(t, Handler{}, handlers["b"])
require.Len(t, commands, 3)
require.Equal(t, KeeperA{
key: KVStoreKey{name: "a"},
key: KVStoreKey{name: "a"},
name: "a",
}, a)
require.Equal(t, KeeperB{
key: KVStoreKey{name: "b"},
Expand All @@ -104,11 +100,8 @@ func TestScenario(t *testing.T) {
},
}, b)
},
container.Provide(
ProvideKVStoreKey,
ProvideModuleKey,
ProvideMsgClientA,
),
container.Provide(ProvideMsgClientA),
container.ProvideInModule("runtime", ProvideKVStoreKey),
container.ProvideInModule("a", wrapMethod0(ModuleA{})),
container.ProvideInModule("b", wrapMethod0(ModuleB{})),
))
Expand Down
23 changes: 15 additions & 8 deletions container/module_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ import (

// ModuleKey is a special type used to scope a provider to a "module".
//
// Special module-scoped providers can be used with Provide by declaring a
// provider with an input parameter of type ModuleKey. These providers
// may construct a unique value of a dependency for each module and will
// be called at most once per module.
// Special module-scoped providers can be used with Provide and ProvideInModule
// by declaring a provider with an input parameter of type ModuleKey. These
// providers may construct a unique value of a dependency for each module and
// will be called at most once per module.
//
// Providers passed to ProvideInModule can also declare an input parameter
// of type ModuleKey to retrieve their module key but these providers will be
// called at most once.
// When being used with ProvideInModule, the provider will not receive its
// own ModuleKey but rather the key of the module requesting the dependency
// so that modules can provide module-scoped dependencies to other modules.
//
// In order for a module to retrieve their own module key they can define
// a provider which requires the OwnModuleKey type and DOES NOT require ModuleKey.
type ModuleKey struct {
*moduleKey
}
Expand All @@ -28,4 +31,8 @@ func (k ModuleKey) Name() string {

var moduleKeyType = reflect.TypeOf(ModuleKey{})

var stringType = reflect.TypeOf("")
// OwnModuleKey is a type which can be used in a module to retrieve its own
// ModuleKey. It MUST NOT be used together with a ModuleKey dependency.
type OwnModuleKey ModuleKey

var ownModuleKeyType = reflect.TypeOf((*OwnModuleKey)(nil)).Elem()

0 comments on commit 624539a

Please sign in to comment.