fix!(container): fix issue with providing a module-scoped dependency from within a module (#11913)
This commit is contained in:
parent
10af6f9d82
commit
624539a9f3
|
@ -133,6 +133,8 @@ func (c *container) getResolver(typ reflect.Type) (resolver, error) {
|
||||||
return c.resolvers[typ], nil
|
return c.resolvers[typ], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var stringType = reflect.TypeOf("")
|
||||||
|
|
||||||
func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (interface{}, error) {
|
func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (interface{}, error) {
|
||||||
providerGraphNode, err := c.locationGraphNode(provider.Location, key)
|
providerGraphNode, err := c.locationGraphNode(provider.Location, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -140,12 +142,17 @@ func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (inter
|
||||||
}
|
}
|
||||||
|
|
||||||
hasModuleKeyParam := false
|
hasModuleKeyParam := false
|
||||||
|
hasOwnModuleKeyParam := false
|
||||||
for _, in := range provider.Inputs {
|
for _, in := range provider.Inputs {
|
||||||
typ := in.Type
|
typ := in.Type
|
||||||
if typ == moduleKeyType {
|
if typ == moduleKeyType {
|
||||||
hasModuleKeyParam = true
|
hasModuleKeyParam = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if typ == ownModuleKeyType {
|
||||||
|
hasOwnModuleKeyParam = true
|
||||||
|
}
|
||||||
|
|
||||||
if isAutoGroupType(typ) {
|
if isAutoGroupType(typ) {
|
||||||
return nil, fmt.Errorf("auto-group type %v can't be used as an input parameter", typ)
|
return nil, fmt.Errorf("auto-group type %v can't be used as an input parameter", typ)
|
||||||
} else if isOnePerModuleType(typ) {
|
} else if isOnePerModuleType(typ) {
|
||||||
|
@ -170,7 +177,7 @@ func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (inter
|
||||||
c.addGraphEdge(typeGraphNode, providerGraphNode)
|
c.addGraphEdge(typeGraphNode, providerGraphNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if key != nil || !hasModuleKeyParam {
|
if !hasModuleKeyParam {
|
||||||
c.logf("Registering %s", provider.Location.String())
|
c.logf("Registering %s", provider.Location.String())
|
||||||
c.indentLogger()
|
c.indentLogger()
|
||||||
defer c.dedentLogger()
|
defer c.dedentLogger()
|
||||||
|
@ -227,6 +234,11 @@ func (c *container) addNode(provider *ProviderDescriptor, key *moduleKey) (inter
|
||||||
|
|
||||||
return sp, nil
|
return sp, nil
|
||||||
} else {
|
} 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.logf("Registering module-scoped provider: %s", provider.Location.String())
|
||||||
c.indentLogger()
|
c.indentLogger()
|
||||||
defer c.dedentLogger()
|
defer c.dedentLogger()
|
||||||
|
@ -314,6 +326,15 @@ func (c *container) resolve(in ProviderInput, moduleKey *moduleKey, caller Locat
|
||||||
return reflect.ValueOf(ModuleKey{moduleKey}), nil
|
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)
|
vr, err := c.getResolver(in.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return reflect.Value{}, err
|
return reflect.Value{}, err
|
||||||
|
|
|
@ -15,14 +15,13 @@ type KVStoreKey struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModuleKey string
|
|
||||||
|
|
||||||
type MsgClientA struct {
|
type MsgClientA struct {
|
||||||
key ModuleKey
|
key string
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeeperA struct {
|
type KeeperA struct {
|
||||||
key KVStoreKey
|
key KVStoreKey
|
||||||
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeeperB struct {
|
type KeeperB struct {
|
||||||
|
@ -46,18 +45,14 @@ func ProvideKVStoreKey(moduleKey container.ModuleKey) KVStoreKey {
|
||||||
return KVStoreKey{name: moduleKey.Name()}
|
return KVStoreKey{name: moduleKey.Name()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideModuleKey(moduleKey container.ModuleKey) (ModuleKey, error) {
|
func ProvideMsgClientA(key container.ModuleKey) MsgClientA {
|
||||||
return ModuleKey(moduleKey.Name()), nil
|
return MsgClientA{key.Name()}
|
||||||
}
|
|
||||||
|
|
||||||
func ProvideMsgClientA(_ container.ModuleKey, key ModuleKey) MsgClientA {
|
|
||||||
return MsgClientA{key}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModuleA struct{}
|
type ModuleA struct{}
|
||||||
|
|
||||||
func (ModuleA) Provide(key KVStoreKey) (KeeperA, Handler, Command) {
|
func (ModuleA) Provide(key KVStoreKey, moduleKey container.OwnModuleKey) (KeeperA, Handler, Command) {
|
||||||
return KeeperA{key}, Handler{}, Command{}
|
return KeeperA{key: key, name: container.ModuleKey(moduleKey).Name()}, Handler{}, Command{}
|
||||||
}
|
}
|
||||||
|
|
||||||
type ModuleB struct{}
|
type ModuleB struct{}
|
||||||
|
@ -76,7 +71,7 @@ type BProvides struct {
|
||||||
Commands []Command
|
Commands []Command
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ModuleB) Provide(dependencies BDependencies, _ container.ModuleKey) (BProvides, Handler, error) {
|
func (ModuleB) Provide(dependencies BDependencies) (BProvides, Handler, error) {
|
||||||
return BProvides{
|
return BProvides{
|
||||||
KeeperB: KeeperB{
|
KeeperB: KeeperB{
|
||||||
key: dependencies.Key,
|
key: dependencies.Key,
|
||||||
|
@ -96,6 +91,7 @@ func TestScenario(t *testing.T) {
|
||||||
require.Len(t, commands, 3)
|
require.Len(t, commands, 3)
|
||||||
require.Equal(t, KeeperA{
|
require.Equal(t, KeeperA{
|
||||||
key: KVStoreKey{name: "a"},
|
key: KVStoreKey{name: "a"},
|
||||||
|
name: "a",
|
||||||
}, a)
|
}, a)
|
||||||
require.Equal(t, KeeperB{
|
require.Equal(t, KeeperB{
|
||||||
key: KVStoreKey{name: "b"},
|
key: KVStoreKey{name: "b"},
|
||||||
|
@ -104,11 +100,8 @@ func TestScenario(t *testing.T) {
|
||||||
},
|
},
|
||||||
}, b)
|
}, b)
|
||||||
},
|
},
|
||||||
container.Provide(
|
container.Provide(ProvideMsgClientA),
|
||||||
ProvideKVStoreKey,
|
container.ProvideInModule("runtime", ProvideKVStoreKey),
|
||||||
ProvideModuleKey,
|
|
||||||
ProvideMsgClientA,
|
|
||||||
),
|
|
||||||
container.ProvideInModule("a", wrapMethod0(ModuleA{})),
|
container.ProvideInModule("a", wrapMethod0(ModuleA{})),
|
||||||
container.ProvideInModule("b", wrapMethod0(ModuleB{})),
|
container.ProvideInModule("b", wrapMethod0(ModuleB{})),
|
||||||
))
|
))
|
||||||
|
|
|
@ -6,14 +6,17 @@ import (
|
||||||
|
|
||||||
// ModuleKey is a special type used to scope a provider to a "module".
|
// 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
|
// Special module-scoped providers can be used with Provide and ProvideInModule
|
||||||
// provider with an input parameter of type ModuleKey. These providers
|
// by declaring a provider with an input parameter of type ModuleKey. These
|
||||||
// may construct a unique value of a dependency for each module and will
|
// providers may construct a unique value of a dependency for each module and
|
||||||
// be called at most once per module.
|
// will be called at most once per module.
|
||||||
//
|
//
|
||||||
// Providers passed to ProvideInModule can also declare an input parameter
|
// When being used with ProvideInModule, the provider will not receive its
|
||||||
// of type ModuleKey to retrieve their module key but these providers will be
|
// own ModuleKey but rather the key of the module requesting the dependency
|
||||||
// called at most once.
|
// 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 {
|
type ModuleKey struct {
|
||||||
*moduleKey
|
*moduleKey
|
||||||
}
|
}
|
||||||
|
@ -28,4 +31,8 @@ func (k ModuleKey) Name() string {
|
||||||
|
|
||||||
var moduleKeyType = reflect.TypeOf(ModuleKey{})
|
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()
|
||||||
|
|
Loading…
Reference in New Issue