Skip to content

Commit

Permalink
fix: funcResults should key by *ast.FuncType
Browse files Browse the repository at this point in the history
  • Loading branch information
morlay committed Apr 8, 2024
1 parent a9c931c commit 30a8ca0
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 131 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/octohelm/x v0.0.0-20240219080259-91528f21e203
github.com/onsi/gomega v1.31.1
github.com/pkg/errors v0.9.1
golang.org/x/sync v0.7.0
golang.org/x/text v0.14.0
golang.org/x/tools v0.20.0
)
Expand All @@ -17,7 +18,6 @@ require (
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sync v0.7.0 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
13 changes: 3 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,16 @@ github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo=
github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
2 changes: 0 additions & 2 deletions pkg/gengo/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ func (c *context) pkgExecute(ctx corecontext.Context, pkg string, generators ...
}

gfs := sync.Map{}

eg := &errgroup.Group{}

for i := range generators {
Expand All @@ -131,7 +130,6 @@ func (c *context) pkgExecute(ctx corecontext.Context, pkg string, generators ...
pkgCtxForGen.l = logr.FromContext(ctx).WithValues("gengo", g.Name())

if e := pkgCtxForGen.doGenerate(ctx, g); e != nil {

return errors.Wrapf(e, "`%s` generate failed for %s", g.Name(), pkgCtx.pkg.Pkg().Path())
}

Expand Down
2 changes: 0 additions & 2 deletions pkg/gengo/genfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ import (
"github.com/octohelm/gengo/pkg/namer"
)

type genfiles map[string]*genfile

func newGenfile() *genfile {
return &genfile{
imports: namer.NewDefaultImportTracker(),
Expand Down
228 changes: 120 additions & 108 deletions pkg/types/function_results.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"go/ast"
"go/constant"
"go/types"
"sync"
)

type Results []TypeAndValues
Expand Down Expand Up @@ -101,16 +102,6 @@ func (pi *pkgInfo) ResultsOf(typeFunc *types.Func) (Results, int) {
}

func (pi *pkgInfo) resolveFuncResults(s *types.Signature) (finalFuncResults Results) {
if r, ok := pi.funcResults[s]; ok {
return r
}

// registry before process to avoid stackoverflow
pi.funcResults[s] = finalFuncResults
defer func() {
pi.funcResults[s] = finalFuncResults
}()

resultTypes := s.Results()
n := resultTypes.Len()

Expand Down Expand Up @@ -161,136 +152,157 @@ func (pi *pkgInfo) resolveFuncResults(s *types.Signature) (finalFuncResults Resu
}
}

return
return nil
}

func (pi *pkgInfo) funcResultsFrom(s *types.Signature, funcType *ast.FuncType, body *ast.BlockStmt) (finalFuncResults Results) {
n := s.Results().Len()
finalFuncResults = make(Results, n)

if funcType == nil || body == nil {
func (pi *pkgInfo) funcResultsFrom(s *types.Signature, funcType *ast.FuncType, body *ast.BlockStmt) Results {
if funcType == nil {
return nil
}

namedResults := make([]*ast.Ident, 0)

for _, field := range funcType.Results.List {
namedResults = append(namedResults, field.Names...)
if v, ok := pi.funcResults.Load(funcType); ok {
if v != nil {
return v.(Results)
}
}

variableLatestAssigns := map[*ast.Object]TypeAndValue{}
get, _ := pi.funcResultResolvers.LoadOrStore(funcType, sync.OnceValue(func() (finalFuncResults Results) {
// avoid loop
pi.funcResults.Store(funcType, finalFuncResults)

assign := func(o *ast.Object, rhs []ast.Expr, n int, i int) {
if len(rhs) == n {
variableLatestAssigns[o] = TypeAndValue{Expr: rhs[i]}
} else {
variableLatestAssigns[o] = TypeAndValue{Expr: rhs[0], At: i}
defer func() {
pi.funcResults.Store(funcType, finalFuncResults)
}()

n := s.Results().Len()
finalFuncResults = make(Results, n)

if funcType == nil || body == nil {
return nil
}
}

var typeAndValueOf func(at int, expr ast.Expr) TypeAndValue
namedResults := make([]*ast.Ident, 0)

typeAndValueOf = func(at int, expr ast.Expr) (final TypeAndValue) {
switch x := expr.(type) {
case *ast.Ident:
if x.Obj != nil {
if tve, ok := variableLatestAssigns[x.Obj]; ok {
return typeAndValueOf(tve.At, tve.Expr)
}
}
case *ast.SelectorExpr:
if x.Sel.Obj != nil {
if tve, ok := variableLatestAssigns[x.Sel.Obj]; ok {
return typeAndValueOf(tve.At, tve.Expr)
}
}
case *ast.CallExpr:
switch callX := pi.Package.TypesInfo.TypeOf(x.Fun).(type) {
case *types.Signature:
final.At = at
final.Expr = expr
for _, field := range funcType.Results.List {
namedResults = append(namedResults, field.Names...)
}

rets := callX.Results()
shouldDeepResolve := false
variableLatestAssigns := map[*ast.Object]TypeAndValue{}

for i := 0; i < rets.Len(); i++ {
t := rets.At(i).Type()
assign := func(o *ast.Object, rhs []ast.Expr, n int, i int) {
if len(rhs) == n {
variableLatestAssigns[o] = TypeAndValue{Expr: rhs[i]}
} else {
variableLatestAssigns[o] = TypeAndValue{Expr: rhs[0], At: i}
}
}

var typeAndValueOf func(at int, expr ast.Expr) TypeAndValue

switch t.String() {
case "error", "any", "interface{}":
shouldDeepResolve = true
typeAndValueOf = func(at int, expr ast.Expr) (final TypeAndValue) {
switch x := expr.(type) {
case *ast.Ident:
if x.Obj != nil {
if tve, ok := variableLatestAssigns[x.Obj]; ok {
return typeAndValueOf(tve.At, tve.Expr)
}
}

if final.At < rets.Len() {
final.Type = rets.At(final.At).Type()
} else {
final.Type = rets.At(0).Type()
case *ast.SelectorExpr:
if x.Sel.Obj != nil {
if tve, ok := variableLatestAssigns[x.Sel.Obj]; ok {
return typeAndValueOf(tve.At, tve.Expr)
}
}
case *ast.CallExpr:
switch callX := pi.Package.TypesInfo.TypeOf(x.Fun).(type) {
case *types.Signature:
final.At = at
final.Expr = expr

rets := callX.Results()
shouldDeepResolve := false

for i := 0; i < rets.Len(); i++ {
t := rets.At(i).Type()

switch t.String() {
case "error", "any", "interface{}":
shouldDeepResolve = true
}
}

if shouldDeepResolve {
final.From = pi.resolveFuncResults(callX)
}
if final.At < rets.Len() {
final.Type = rets.At(final.At).Type()
} else {
final.Type = rets.At(0).Type()
}

return final
if shouldDeepResolve {
final.From = pi.resolveFuncResults(callX)
}

return final
}
}
}

tv, _ := pi.Eval(expr)
tv, _ := pi.Eval(expr)

final.Type = tv.Type
final.Value = tv.Value
final.At = at
final.Expr = expr
final.Type = tv.Type
final.Value = tv.Value
final.At = at
final.Expr = expr

return
}
return
}

ast.Inspect(body, func(node ast.Node) bool {
switch x := node.(type) {
case *ast.FuncLit:
// skip func lit
return false
case *ast.AssignStmt:
// set var by code flow
// not support side effect assign
for i := range x.Lhs {
switch lhs := x.Lhs[i].(type) {
// assign to variable
case *ast.Ident:
if lhs.Obj != nil {
assign(lhs.Obj, x.Rhs, len(x.Lhs), i)
}
// assign to field
case *ast.SelectorExpr:
if lhs.Sel != nil {
assign(lhs.Sel.Obj, x.Rhs, len(x.Lhs), i)
ast.Inspect(body, func(node ast.Node) bool {
switch x := node.(type) {
case *ast.FuncLit:
// skip func lit
return false
case *ast.AssignStmt:
// set var by code flow
// not support side effect assign
for i := range x.Lhs {
switch lhs := x.Lhs[i].(type) {
// assign to variable
case *ast.Ident:
if lhs.Obj != nil {
assign(lhs.Obj, x.Rhs, len(x.Lhs), i)
}
// assign to field
case *ast.SelectorExpr:
if lhs.Sel != nil {
assign(lhs.Sel.Obj, x.Rhs, len(x.Lhs), i)
}
}
}
}
case *ast.ReturnStmt:
results := x.Results
case *ast.ReturnStmt:
results := x.Results

// fill return resolveFuncResults by named resolveFuncResults
if x.Results == nil {
results = make([]ast.Expr, n)
// fill return resolveFuncResults by named resolveFuncResults
if x.Results == nil {
results = make([]ast.Expr, n)

for i := range namedResults {
results[i] = namedResults[i]
for i := range namedResults {
results[i] = namedResults[i]
}
}
}

for at := 0; at < n; at++ {
if len(results) == n {
finalFuncResults[at] = append(finalFuncResults[at], typeAndValueOf(at, results[at]))
} else {
finalFuncResults[at] = append(finalFuncResults[at], typeAndValueOf(at, results[0]))
for at := 0; at < n; at++ {
if len(results) == n {
finalFuncResults[at] = append(finalFuncResults[at], typeAndValueOf(at, results[at]))
} else {
finalFuncResults[at] = append(finalFuncResults[at], typeAndValueOf(at, results[0]))
}
}
}
}

return true
})
return true
})

return
}))

return
return get.(func() Results)()
}
17 changes: 9 additions & 8 deletions pkg/types/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"go/ast"
"go/token"
"go/types"
"golang.org/x/tools/go/packages"
"path/filepath"
"strings"

"golang.org/x/tools/go/packages"
"sync"
)

type Module struct {
Expand Down Expand Up @@ -70,9 +70,8 @@ func newPkg(pkg *packages.Package, u Universe) Package {
endLineToCommentGroup: map[fileLine]*ast.CommentGroup{},
endLineToTrailingCommentGroup: map[fileLine]*ast.CommentGroup{},

signatures: map[*types.Signature]ast.Node{},
funcDecls: map[*types.Func]ast.Node{},
funcResults: map[*types.Signature][]TypeAndValues{},
signatures: map[*types.Signature]ast.Node{},
funcDecls: map[*types.Func]ast.Node{},

constants: map[string]*types.Const{},
types: map[string]*types.TypeName{},
Expand Down Expand Up @@ -235,9 +234,11 @@ type pkgInfo struct {
endLineToCommentGroup map[fileLine]*ast.CommentGroup
endLineToTrailingCommentGroup map[fileLine]*ast.CommentGroup

funcResults map[*types.Signature][]TypeAndValues
signatures map[*types.Signature]ast.Node
funcDecls map[*types.Func]ast.Node
funcDecls map[*types.Func]ast.Node
signatures map[*types.Signature]ast.Node

funcResults sync.Map
funcResultResolvers sync.Map
}

func (pi *pkgInfo) SourceDir() string {
Expand Down

0 comments on commit 30a8ca0

Please sign in to comment.