diff --git a/builtin.go b/builtin.go index e94422e..d965efa 100644 --- a/builtin.go +++ b/builtin.go @@ -1142,7 +1142,7 @@ func (p addableT) Match(pkg *Package, typ types.Type) bool { // TODO: refactor cb := pkg.cb cb.stk.Push(elemNone) - kind := cb.findMember(typ, "Gop_Add", "", MemberFlagVal, &Element{}, nil) + kind := cb.findMember(typ, "Gop_Add", "", MemberFlagVal, &Element{}, nil, nil) if kind != 0 { cb.stk.PopN(1) if kind == MemberMethod { diff --git a/codebuild.go b/codebuild.go index aa63a34..a99fd9e 100644 --- a/codebuild.go +++ b/codebuild.go @@ -1569,7 +1569,7 @@ func (p *CodeBuilder) Member(name string, flag MemberFlag, src ...ast.Node) (kin flag = memberFlagMethodToFunc } aliasName, flag = aliasNameOf(name, flag) - kind = p.findMember(at, name, aliasName, flag, arg, srcExpr) + kind = p.findMember(at, name, aliasName, flag, arg, srcExpr, nil) if isType && kind != MemberMethod { code, pos := p.loadExpr(srcExpr) return MemberInvalid, p.newCodeError( @@ -1617,7 +1617,15 @@ func getUnderlying(pkg *Package, typ types.Type) types.Type { } func (p *CodeBuilder) findMember( - typ types.Type, name, aliasName string, flag MemberFlag, arg *Element, srcExpr ast.Node) MemberKind { + typ types.Type, name, aliasName string, flag MemberFlag, arg *Element, srcExpr ast.Node, visited map[types.Type]struct{}) MemberKind { + if visited == nil { + visited = make(map[types.Type]struct{}) + } + if _, ok := visited[typ]; ok { + return MemberInvalid + } + visited[typ] = struct{}{} + var named *types.Named retry: switch o := typ.(type) { @@ -1635,10 +1643,10 @@ retry: return kind } if fstruc { - return p.embeddedField(struc, name, aliasName, flag, arg, srcExpr) + return p.embeddedField(struc, name, aliasName, flag, arg, srcExpr, visited) } case *types.Struct: - if kind := p.field(t, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { + if kind := p.field(t, name, aliasName, flag, arg, srcExpr, visited); kind != MemberInvalid { return kind } } @@ -1649,7 +1657,7 @@ retry: } goto retry case *types.Struct: - if kind := p.field(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid { + if kind := p.field(o, name, aliasName, flag, arg, srcExpr, visited); kind != MemberInvalid { return kind } if named != nil { @@ -1829,10 +1837,10 @@ func (p *CodeBuilder) normalField( } func (p *CodeBuilder) embeddedField( - o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) MemberKind { + o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node, visited map[types.Type]struct{}) MemberKind { for i, n := 0, o.NumFields(); i < n; i++ { if fld := o.Field(i); fld.Embedded() { - if kind := p.findMember(fld.Type(), name, aliasName, flag, arg, src); kind != MemberInvalid { + if kind := p.findMember(fld.Type(), name, aliasName, flag, arg, src, visited); kind != MemberInvalid { return kind } } @@ -1841,11 +1849,11 @@ func (p *CodeBuilder) embeddedField( } func (p *CodeBuilder) field( - o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) MemberKind { + o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node, visited map[types.Type]struct{}) MemberKind { if kind := p.normalField(o, name, arg, src); kind != MemberInvalid { return kind } - return p.embeddedField(o, name, aliasName, flag, arg, src) + return p.embeddedField(o, name, aliasName, flag, arg, src, visited) } func toFuncSig(sig *types.Signature, recv *types.Var) *types.Signature {