Skip to content

Commit

Permalink
proposal: ignore interfaces that contains type constraints (#93)
Browse files Browse the repository at this point in the history
This is a proposal PR to generate mocks without error for following
cases:
```go
type Water[R any, C UnsignedInteger] interface {
	Fish(R) []C
}

type UnsignedInteger interface {
	~uint | ~uint32 | ~uint64
}
```

Go `types` package seems to wrap interfaces that contain type
constraints by checking a type set literal of the form `~T` and `A|B`.
https://github.com/golang/go/blob/master/src/go/types/decl.go#L668

So gomock can just ignore that pattern to generate mocks safely without
`don't know how to mock method of type` errors. I think this can be a
better solution for custom type constraints than [`-exclude`
flag](#72).

---------

Co-authored-by: Jacob Oaks <[email protected]>
  • Loading branch information
hoonmin and JacobOaks authored Sep 25, 2023
1 parent fcaca4a commit 7842e1d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 24 deletions.
14 changes: 14 additions & 0 deletions mockgen/generic_go118.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
package main

import (
"errors"
"fmt"
"go/ast"
"go/token"
"strings"

"go.uber.org/mock/mockgen/model"
Expand Down Expand Up @@ -98,6 +100,16 @@ func (p *fileParser) parseGenericMethod(field *ast.Field, it *namedInterface, if
case *ast.IndexListExpr:
indices = v.Indices
typ = v.X
case *ast.UnaryExpr:
if v.Op == token.TILDE {
return nil, errConstraintInterface
}
return nil, fmt.Errorf("~T may only appear as constraint for %T", field.Type)
case *ast.BinaryExpr:
if v.Op == token.OR {
return nil, errConstraintInterface
}
return nil, fmt.Errorf("A|B may only appear as constraint for %T", field.Type)
default:
return nil, fmt.Errorf("don't know how to mock method of type %T", field.Type)
}
Expand All @@ -114,3 +126,5 @@ func (p *fileParser) parseGenericMethod(field *ast.Field, it *namedInterface, if

return p.parseMethod(nf, it, iface, pkg, tps)
}

var errConstraintInterface = errors.New("interface contains constraints")
8 changes: 8 additions & 0 deletions mockgen/internal/tests/generics/generics.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,11 @@ type SolarSystem[T constraints.Ordered] interface {
type Earth[R any] interface {
Water(R) []R
}

type Water[R any, C UnsignedInteger] interface {
Fish(R) []C
}

type UnsignedInteger interface {
~uint | ~uint32 | ~uint64
}
66 changes: 42 additions & 24 deletions mockgen/internal/tests/generics/source/mock_generics_mock.go

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

3 changes: 3 additions & 0 deletions mockgen/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ func (p *fileParser) parseFile(importPath string, file *ast.File) (*model.Packag
continue
}
i, err := p.parseInterface(ni.name.String(), importPath, ni)
if errors.Is(err, errConstraintInterface) {
continue
}
if err != nil {
return nil, err
}
Expand Down

0 comments on commit 7842e1d

Please sign in to comment.