Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(subtract): added Subtract function to wire #382

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
118 changes: 115 additions & 3 deletions internal/wire/parse.go
Expand Up @@ -546,6 +546,9 @@
case "NewSet":
pset, errs := oc.processNewSet(info, pkgPath, call, nil, varName)
return pset, notePositionAll(exprPos, errs)
case "Subtract":
pset, errs := oc.processSubtract(info, pkgPath, call, nil, varName)
return pset, notePositionAll(exprPos, errs)
case "Bind":
b, err := processBind(oc.fset, info, call)
if err != nil {
Expand Down Expand Up @@ -590,6 +593,115 @@
return nil, []error{notePosition(exprPos, errors.New("unknown pattern"))}
}

func (oc *objectCache) filterType(set *ProviderSet, t types.Type) []error {
hasType := func(outs []types.Type) bool {
for _, o := range outs {
if types.Identical(o, t) {
return true
}
pt, ok := o.(*types.Pointer)
if ok && types.Identical(pt.Elem(), t) {
return true
}
}
return false
}

providers := make([]*Provider, 0, len(set.Providers))
for _, p := range set.Providers {
if !hasType(p.Out) {
providers = append(providers, p)
}
}
set.Providers = providers

bindings := make([]*IfaceBinding, 0, len(set.Bindings))
for _, i := range set.Bindings {
if !types.Identical(i.Iface, t) {
bindings = append(bindings, i)
}
}
set.Bindings = bindings

values := make([]*Value, 0, len(set.Values))
for _, v := range set.Values {
if !types.Identical(v.Out, t) {
values = append(values, v)

Check warning on line 629 in internal/wire/parse.go

View check run for this annotation

Codecov / codecov/patch

internal/wire/parse.go#L628-L629

Added lines #L628 - L629 were not covered by tests
}
}
set.Values = values

fields := make([]*Field, 0, len(set.Fields))
for _, f := range set.Fields {
if !hasType(f.Out) {
fields = append(fields, f)

Check warning on line 637 in internal/wire/parse.go

View check run for this annotation

Codecov / codecov/patch

internal/wire/parse.go#L636-L637

Added lines #L636 - L637 were not covered by tests
}
}
set.Fields = fields

imports := make([]*ProviderSet, 0, len(set.Imports))
for _, p := range set.Imports {
clone := *p
if errs := oc.filterType(&clone, t); len(errs) > 0 {
return errs

Check warning on line 646 in internal/wire/parse.go

View check run for this annotation

Codecov / codecov/patch

internal/wire/parse.go#L646

Added line #L646 was not covered by tests
}
imports = append(imports, &clone)
}
set.Imports = imports

var errs []error
set.providerMap, set.srcMap, errs = buildProviderMap(oc.fset, oc.hasher, set)
if len(errs) > 0 {
return errs

Check warning on line 655 in internal/wire/parse.go

View check run for this annotation

Codecov / codecov/patch

internal/wire/parse.go#L655

Added line #L655 was not covered by tests
}
return nil
}

func (oc *objectCache) processSubtract(info *types.Info, pkgPath string, call *ast.CallExpr, args *InjectorArgs, varName string) (interface{}, []error) {
// Assumes that call.Fun is wire.Subtract.
if len(call.Args) < 2 {
return nil, []error{notePosition(oc.fset.Position(call.Pos()),
errors.New("call to Subtract must specify types to be subtracted"))}
}
firstArg, errs := oc.processExpr(info, pkgPath, call.Args[0], "")
if len(errs) > 0 {
return nil, errs

Check warning on line 668 in internal/wire/parse.go

View check run for this annotation

Codecov / codecov/patch

internal/wire/parse.go#L668

Added line #L668 was not covered by tests
}
set, ok := firstArg.(*ProviderSet)
if !ok {
return nil, []error{notePosition(oc.fset.Position(call.Pos()),
fmt.Errorf("first argument to Subtract must be a Set")),
}
}
pset := &ProviderSet{
Pos: call.Pos(),
InjectorArgs: args,
PkgPath: pkgPath,
VarName: varName,
// Copy the other fields.
Providers: set.Providers,
Bindings: set.Bindings,
Values: set.Values,
Fields: set.Fields,
Imports: set.Imports,
}
ec := new(errorCollector)
for _, arg := range call.Args[1:] {
ptr, ok := info.TypeOf(arg).(*types.Pointer)
if !ok {
ec.add(notePosition(oc.fset.Position(arg.Pos()),
errors.New("argument to Subtract must be a pointer"),
))
continue
}
ec.add(oc.filterType(pset, ptr.Elem())...)
}
if len(ec.errors) > 0 {
return nil, ec.errors
}
return pset, nil
}

func (oc *objectCache) processNewSet(info *types.Info, pkgPath string, call *ast.CallExpr, args *InjectorArgs, varName string) (*ProviderSet, []error) {
// Assumes that call.Fun is wire.NewSet or wire.Build.

Expand Down Expand Up @@ -1173,9 +1285,9 @@
//
// - For a function provider, this is the first return value type.
// - For a struct provider, this is either the struct type or the pointer type
// whose element type is the struct type.
// - For a value, this is the type of the expression.
// - For an argument, this is the type of the argument.
// whose element type is the struct type.
// - For a value, this is the type of the expression.
// - For an argument, this is the type of the argument.
func (pt ProvidedType) Type() types.Type {
return pt.t
}
Expand Down
66 changes: 66 additions & 0 deletions internal/wire/testdata/Subtract/foo/foo.go
@@ -0,0 +1,66 @@
// Copyright 2018 The Wire Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/google/wire"
)

type context struct{}

func main() {}

type FooOptions struct{}
type Foo string
type Bar struct{}
type BarName string

func (b *Bar) Bar() {}

func provideFooOptions() *FooOptions {
return &FooOptions{}
}

func provideFoo(*FooOptions) Foo {
return Foo("foo")
}

func provideBar(Foo, BarName) *Bar {
return &Bar{}
}

type BarService interface {
Bar()
}

type FooBar struct {
BarService
Foo
}

var Set = wire.NewSet(
provideFooOptions,
provideFoo,
provideBar,
)

var SuperSet = wire.NewSet(Set,
wire.Struct(new(FooBar), "*"),
wire.Bind(new(BarService), new(*Bar)),
)

type FakeBarService struct{}

func (f *FakeBarService) Bar() {}
47 changes: 47 additions & 0 deletions internal/wire/testdata/Subtract/foo/wire.go
@@ -0,0 +1,47 @@
// Copyright 2018 The Wire Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build wireinject
// +build wireinject

package main

import (
"github.com/google/wire"
)

func inject(name BarName, opts *FooOptions) *Bar {
panic(wire.Build(wire.Subtract(Set, new(FooOptions))))
}

func injectBarService(name BarName, opts *FakeBarService) *FooBar {
panic(wire.Build(
wire.Subtract(SuperSet, new(BarService)),
wire.Bind(new(BarService), new(*FakeBarService)),
))
}

func injectFooBarService(name BarName, opts *FooOptions, bar *FakeBarService) *FooBar {
panic(wire.Build(
wire.Subtract(SuperSet, new(FooOptions), new(BarService)),
wire.Bind(new(BarService), new(*FakeBarService)),
))
}

func injectNone(name BarName, foo Foo, bar *FakeBarService) *FooBar {
panic(wire.Build(
wire.Subtract(SuperSet, new(Foo), new(BarService)),
wire.Bind(new(BarService), new(*FakeBarService)),
))
}
1 change: 1 addition & 0 deletions internal/wire/testdata/Subtract/pkg
@@ -0,0 +1 @@
example.com/foo
Empty file.
42 changes: 42 additions & 0 deletions internal/wire/testdata/Subtract/want/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions internal/wire/testdata/SubtractErrors/foo/foo.go
@@ -0,0 +1,46 @@
// Copyright 2018 The Wire Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"github.com/google/wire"
)

type context struct{}

func main() {}

type FooOptions struct{}
type Foo string
type Bar struct{}
type BarName string

func provideFooOptions() *FooOptions {
return &FooOptions{}
}

func provideFoo(*FooOptions) Foo {
return Foo("foo")
}

func provideBar(Foo, BarName) *Bar {
return &Bar{}
}

var Set = wire.NewSet(
provideFooOptions,
provideFoo,
provideBar,
)
34 changes: 34 additions & 0 deletions internal/wire/testdata/SubtractErrors/foo/wire.go
@@ -0,0 +1,34 @@
// Copyright 2018 The Wire Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build wireinject
// +build wireinject

package main

import (
"github.com/google/wire"
)

func injectMissArgs(opts *FooOptions) Foo {
panic(wire.Build(wire.Subtract(provideFoo)))
}

func injectNonSet(opts *FooOptions) Foo {
panic(wire.Build(wire.Subtract(provideFoo, new(FooOptions))))
}

func injectNonPointer(name BarName, opts *FooOptions) *Bar {
panic(wire.Build(wire.Subtract(Set, FooOptions{})))
}
1 change: 1 addition & 0 deletions internal/wire/testdata/SubtractErrors/pkg
@@ -0,0 +1 @@
example.com/foo
5 changes: 5 additions & 0 deletions internal/wire/testdata/SubtractErrors/want/wire_errs.txt
@@ -0,0 +1,5 @@
example.com/foo/wire.go:x:y: call to Subtract must specify types to be subtracted

example.com/foo/wire.go:x:y: first argument to Subtract must be a Set

example.com/foo/wire.go:x:y: argument to Subtract must be a pointer