Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions codebuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -1145,11 +1145,11 @@ func (p *CodeBuilder) staticMember(typ types.Type, name string, flag MemberFlag,
return MemberInvalid, nil
}
p.ensureLoaded(named)
method, obj := lookupStaticMember(named, name)
_, obj := lookupStaticMember(named, name)
if obj == nil {
return MemberInvalid, nil
}
if !p.allowAccess(method.Pkg(), method.Name()) {
if !p.allowAccess(obj.Pkg(), obj.Name()) {
return MemberInvalid, nil
}
if _, ok := obj.(*types.Func); ok {
Expand Down
100 changes: 83 additions & 17 deletions error_msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ func codeErrorTestDo(t *testing.T, pkg *gogen.Package, msg string, source func(p
gogen.WriteTo(&b, pkg, "")
}

func panicErrorTest(t *testing.T, name, msg string, source func()) {
t.Run(name, func(t *testing.T) {
defer func() {
if e := recover(); e != nil {
if ret := fmt.Sprint(e); ret != msg {
t.Fatalf("\nError: \"%s\"\nExpected: \"%s\"\n", ret, msg)
}
} else {
t.Fatal("no error?")
}
}()
source()
})
}

func newFunc(
pkg *gogen.Package, line, column int, rline, rcolumn int,
recv *types.Var, name string, params, results *types.Tuple, variadic bool) *gogen.Func {
Expand Down Expand Up @@ -1778,23 +1793,11 @@ func TestErrStaticMember(t *testing.T) {
EndStmt().
End()
})
const src = `package foo

const XGoPackage = true

type T int

const XGos_T_name = "xgo"
`
gt := newGoxTest()
_, err := gt.LoadGoPackage("foo", "foo.go", src)
if err != nil {
t.Fatal(err)
}
pkg := gt.NewPackage("", "main")
foo := pkg.Import("foo")
typ := foo.Ref("T").Type()
codeErrorTestEx(t, pkg,
fooPkg := types.NewPackage("foo", "foo")
typ := types.NewNamed(types.NewTypeName(token.NoPos, fooPkg, "T", nil), types.Typ[types.Int], nil)
gogen.NewStaticMember(typ, token.NoPos, fooPkg, "name",
types.NewVar(token.NoPos, fooPkg, "xgos_T_name", types.Typ[types.String]))
codeErrorTest(t,
`./foo.gop:1:5: T.name undefined (type foo.T has no method name)`,
func(pkg *gogen.Package) {
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
Expand All @@ -1804,6 +1807,69 @@ const XGos_T_name = "xgo"
})
}

func TestErrStaticMemberConflict(t *testing.T) {
newType := func() (*gogen.Package, *types.Named) {
pkg := newMainPackage()
return pkg, pkg.NewType("T").InitType(pkg, types.Typ[types.Int])
}
newMethod := func(pkg *gogen.Package, name string) *types.Func {
return types.NewFunc(token.NoPos, pkg.Types, name,
types.NewSignatureType(nil, nil, nil, nil, nil, false))
}
newValue := func(pkg *gogen.Package, name string) *types.Var {
return types.NewVar(token.NoPos, pkg.Types, name, types.Typ[types.String])
}

pkg, typ := newType()
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newMethod(pkg, "XGos_T_name"))
panicErrorTest(t, "method then value",
fmt.Sprintf("NewStaticMember: %v.%s conflicts with existing static method\n", typ, "name"),
func() {
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newValue(pkg, "XGos_T_name"))
})

pkg, typ = newType()
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newValue(pkg, "XGos_T_name"))
panicErrorTest(t, "value then method",
fmt.Sprintf("NewStaticMember: %v.%s conflicts with existing static value member\n", typ, "name"),
func() {
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newMethod(pkg, "XGos_T_name"))
})

pkg, typ = newType()
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newValue(pkg, "XGos_T_name"))
panicErrorTest(t, "duplicate value",
fmt.Sprintf("NewStaticMember: %v.%s redeclared as static value member\n", typ, "name"),
func() {
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newValue(pkg, "XGos_T_name2"))
})

pkg, typ = newType()
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newMethod(pkg, "XGos_T_name"))
panicErrorTest(t, "duplicate method",
fmt.Sprintf("NewStaticMember: %v.%s redeclared as static method\n", typ, "name"),
func() {
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newMethod(pkg, "XGos_T_name2"))
})

pkg, typ = newType()
recv := newParam(pkg, token.NoPos, "t", typ)
pkg.NewFunc(recv, "name", nil, nil, false).BodyStart(pkg).End()
panicErrorTest(t, "method then static member",
fmt.Sprintf("NewStaticMember: %v.%s conflicts with existing method\n", typ, "name"),
func() {
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newValue(pkg, "XGos_T_name"))
})
Comment thread
xushiwei marked this conversation as resolved.
codeErrorTest(t,
"./foo.gop:1:5: method name conflicts with existing static value member",
func(pkg *gogen.Package) {
typ := pkg.NewType("T").InitType(pkg, types.Typ[types.Int])
gogen.NewStaticMember(typ, token.NoPos, pkg.Types, "name", newValue(pkg, "XGos_T_name"))
recv := newParam(pkg, token.NoPos, "t", typ)
newFunc(pkg, 1, 5, 1, 10, recv, "name", nil, nil, false).BodyStart(pkg).End()
})
}

func TestErrUnsafe(t *testing.T) {
codeErrorTest(t,
`./foo.gop:6:15: missing argument to function call: unsafe.Sizeof()`,
Expand Down
3 changes: 3 additions & 0 deletions func.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ func (p *Package) NewFuncWith(
return nil, cb.newCodeErrorf(posErr, posErr, "invalid receiver type %v (%v is a pointer type)", typ, typ)
}
if name != "_" { // skip underscore
if _, obj := lookupStaticMember(t, name); obj != nil {
return nil, cb.newCodeErrorf(pos, pos, "method %s conflicts with existing %s", name, staticMemberKind(obj))
}
t.AddMethod(fn.Func)
}
} else if name == "init" { // init is not a normal func
Expand Down
23 changes: 21 additions & 2 deletions func_ext.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,29 @@ func isStaticValueMember(method *types.Func) bool {
return false
}

func staticMemberKind(obj types.Object) string {
if _, ok := obj.(*types.Func); ok {
return "static method"
}
return "static value member"
}

// NewStaticMember associates a package-level object with a named type.
// Function objects resolve as static methods; other objects resolve as static fields.
// Function objects resolve as static methods; other objects resolve as static value members.
// It panics if the registration conflicts with an existing static member or method.
func NewStaticMember(typ *types.Named, pos token.Pos, pkg *types.Package, name string, obj types.Object) *types.Func {
return newMethodEx(typ.Origin(), pos, pkg, name, &TyStaticMember{obj})
typ = typ.Origin()
if method := lookupMethod(typ, name); method != nil {
if old, ok := staticMemberObj(method); ok {
oldKind := staticMemberKind(old)
if newKind := staticMemberKind(obj); newKind == oldKind {
log.Panicf("NewStaticMember: %v.%s redeclared as %s\n", typ, name, newKind)
}
log.Panicf("NewStaticMember: %v.%s conflicts with existing %s\n", typ, name, oldKind)
}
log.Panicf("NewStaticMember: %v.%s conflicts with existing method\n", typ, name)
Comment thread
KurodaKayn marked this conversation as resolved.
}
return newMethodEx(typ, pos, pkg, name, &TyStaticMember{obj})
}
Comment thread
xushiwei marked this conversation as resolved.

func lookupStaticMember(typ *types.Named, name string) (*types.Func, types.Object) {
Expand Down
4 changes: 4 additions & 0 deletions internal/bar/bar.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ func XGos_Game_New() *Game {
return nil
}

const XGos_Game_name = "game"

var XGos_Game_count int

type Info struct {
id int
}
Expand Down
19 changes: 19 additions & 0 deletions xgo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1158,6 +1158,25 @@ func main() {
`)
}

func TestImportedStaticMember(t *testing.T) {
pkg := newMainPackage()
bar := pkg.Import("github.com/goplus/gogen/internal/bar")
game := bar.Ref("Game").Type()
pkg.NewFunc(nil, "main", nil, nil, false).BodyStart(pkg).
DefineVarStart(token.NoPos, "name").Typ(game).MemberVal("name", 0).EndInit(1).
Typ(game).MemberRef("count").IncDec(token.INC).EndStmt().
End()
domTest(t, pkg, `package main

import "github.com/goplus/gogen/internal/bar"

func main() {
name := bar.XGos_Game_name
bar.XGos_Game_count++
}
`)
}

func TestStaticMember(t *testing.T) {
pkg := newMainPackage()
scope := pkg.Types.Scope()
Expand Down
Loading