Skip to content
Draft
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
67 changes: 51 additions & 16 deletions cl/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,6 @@ type pkgCtx struct {
nproj int // number of non-test projects
projs map[string]*gmxProject // .gmx => project
classes map[*ast.File]*gmxClass
overpos map[string]token.Pos // overload => pos
fset *token.FileSet
syms map[string]loader
lbinames []any // names that should load before initGopPkg (can be string/func or *ast.Ident/type)
Expand Down Expand Up @@ -578,7 +577,6 @@ func NewPackage(pkgPath string, pkg *ast.Package, conf *Config) (p *gogen.Packag
nodeInterp: interp,
projs: make(map[string]*gmxProject),
classes: make(map[*ast.File]*gmxClass),
overpos: make(map[string]token.Pos),
syms: make(map[string]loader),
generics: make(map[string]bool),
}
Expand Down Expand Up @@ -750,7 +748,7 @@ func initGopPkg(ctx *pkgCtx, pkg *gogen.Package, gopSyms map[string]bool) {
ctx.loadType(lbi.(*ast.Ident).Name)
}
}
gogen.InitThisGopPkgEx(pkg.Types, ctx.overpos)
gogen.InitThisGopPkg(pkg.Types)
}

func loadFile(ctx *pkgCtx, f *ast.File) {
Expand Down Expand Up @@ -1005,7 +1003,7 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
old, _ := p.SetCurFile(goFile, true)
defer p.RestoreCurFile(old)

preloadFuncDecl := func(d *ast.FuncDecl) {
preloadFuncDecl := func(d *ast.FuncDecl, overload bool) {
if ctx.classRecv != nil { // in class file (.spx/.gmx)
if recv := d.Recv; recv == nil || len(recv.List) == 0 {
d.Recv = ctx.classRecv
Expand All @@ -1018,7 +1016,13 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
fn := func() {
old, _ := p.SetCurFile(goFile, true)
defer p.RestoreCurFile(old)
loadFunc(ctx, nil, fname, d, genFnBody)
if overload {
pkg := ctx.pkg.Types
fn := gogen.NewOverloadFunc(d.Name.Pos(), pkg, fname)
pkg.Scope().Insert(fn)
} else {
loadFunc(ctx, nil, fname, d, genFnBody)
}
}
if fname == "init" {
if genFnBody {
Expand Down Expand Up @@ -1060,7 +1064,13 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
defer p.RestoreCurFile(old)
doInitType(ld)
recv := toRecv(ctx, d.Recv)
loadFunc(ctx, recv, fname, d, genFnBody)
if overload {
pkg := ctx.pkg.Types
typ := pkg.Scope().Lookup(tname).Type().(*types.Named)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security & Quality Issue: Unsafe type lookup/assertion chain. This will panic if Lookup(tname) returns nil or type is not *types.Named.

Suggested change
typ := pkg.Scope().Lookup(tname).Type().(*types.Named)
obj := pkg.Scope().Lookup(tname)
if obj == nil {
ctx.handleErrorf(d.Name.Pos(), d.Name.End(), "type %s not found", tname)
return
}
typ, ok := obj.Type().(*types.Named)
if !ok {
ctx.handleErrorf(d.Name.Pos(), d.Name.End(), "type %s is not a named type", tname)
return
}
gogen.NewOverloadMethod(typ, d.Name.Pos(), pkg, fname)

gogen.NewOverloadMethod(typ, d.Name.Pos(), pkg, fname)
} else {
loadFunc(ctx, recv, fname, d, genFnBody)
}
}
ld.methods = append(ld.methods, fn)
}
Expand Down Expand Up @@ -1194,7 +1204,7 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
}

case *ast.FuncDecl:
preloadFuncDecl(d)
preloadFuncDecl(d, false)

case *ast.OverloadFuncDecl:
var recv *ast.Ident
Expand Down Expand Up @@ -1225,13 +1235,15 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
onames := make([]string, 0, 4)
exov := false
name := d.Name
var hasErr bool
LoopFunc:

for idx, fn := range d.Funcs {
switch expr := fn.(type) {
case *ast.Ident:
if d.Recv != nil && !d.Operator && !d.IsClass {
ctx.handleErrorf(expr.Pos(), expr.End(), "invalid method %v", ctx.LoadExpr(expr))
hasErr = true
break LoopFunc
}
exov = true
Expand All @@ -1251,11 +1263,13 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
case *ast.SelectorExpr:
if d.Recv == nil || d.IsClass {
ctx.handleErrorf(expr.Pos(), expr.End(), "invalid func %v", ctx.LoadExpr(expr))
hasErr = true
break LoopFunc
}
rtyp, ok := checkOverloadMethodRecvType(recv, expr.X)
if !ok {
ctx.handleErrorf(expr.Pos(), expr.End(), "invalid recv type %v", ctx.LoadExpr(expr.X))
hasErr = true
break LoopFunc
}

Expand All @@ -1268,6 +1282,7 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
case *ast.FuncLit:
if d.Recv != nil && !d.Operator && !d.IsClass {
ctx.handleErrorf(expr.Pos(), expr.End(), "invalid method %v", ctx.LoadExpr(expr))
hasErr = true
break LoopFunc
}
name1 := overloadFuncName(name.Name, idx)
Expand All @@ -1282,23 +1297,20 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
Name: id,
Type: expr.Type,
Body: expr.Body,
})
}, false)
default:
ctx.handleErrorf(expr.Pos(), expr.End(), "unknown func %v", ctx.LoadExpr(expr))
hasErr = true
break LoopFunc
}
}

if exov { // need Gopo_xxx
oname, err := overloadName(recv, name.Name, d.Operator)
if err != nil {
ctx.handleErrorf(name.Pos(), name.End(), "%v", err)
break
}
if recv != nil {
ctx.overpos[recv.Name+"."+name.Name] = name.NamePos
} else {
ctx.overpos[name.Name] = name.NamePos
}
oval := strings.Join(onames, ",")
preloadConst(&ast.GenDecl{
Doc: d.Doc,
Expand All @@ -1311,19 +1323,42 @@ func preloadFile(p *gogen.Package, ctx *blockCtx, f *ast.File, goFile string, ge
},
})
ctx.lbinames = append(ctx.lbinames, oname)
} else {
ctx.overpos[name.Name] = name.NamePos
}
if !hasErr {
if d.Recv == nil {
ctx.lbinames = append(ctx.lbinames, d.Name.Name)
}
preloadFuncDecl(&ast.FuncDecl{
Doc: d.Doc,
Recv: d.Recv,
Name: d.Name,
Type: &ast.FuncType{
Params: &ast.FieldList{
List: []*ast.Field{
&ast.Field{
Names: []*ast.Ident{
ast.NewIdent(overloadArgs),
},
Type: ast.NewIdent("any"),
},
},
},
},
}, true)
}
if ctx.rec != nil {
ctx.rec.ReferDef(d.Name, d)
}

default:
log.Panicf("TODO - cl.preloadFile: unknown decl - %T\n", decl)
}
}
}

const (
overloadArgs = "__xgo_overload_args__"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation: Add doc comment explaining this constant's purpose as placeholder parameter name for preloading overload signatures.

Suggested change
overloadArgs = "__xgo_overload_args__"
const (
// overloadArgs is the placeholder parameter name used when preloading overload function
// signatures. This allows overload functions to be registered in the package scope
// during the preload phase before actual implementations are processed.
overloadArgs = "__xgo_overload_args__"
)

)

func checkOverloadMethodRecvType(ot *ast.Ident, recv ast.Expr) (*ast.Ident, bool) {
rtyp, _, ok := getRecvType(recv)
if !ok {
Expand Down
21 changes: 11 additions & 10 deletions x/typesutil/info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2285,16 +2285,17 @@ var d = a.mul(c)
010: 9:30 | *foo *ast.StarExpr | type : *main.foo | type
011: 9:31 | foo *ast.Ident | type : main.foo | type
012: 10: 9 | a *ast.Ident | var : *main.foo | variable
013: 18:10 | *foo *ast.StarExpr | type : *main.foo | type
014: 18:11 | foo *ast.Ident | type : main.foo | type
015: 19: 9 | a *ast.Ident | var : *main.foo | variable
016: 19: 9 | a.mul *ast.SelectorExpr | value : func(b int) *main.foo | value
017: 19: 9 | a.mul(100) *ast.CallExpr | value : *main.foo | value
018: 19:15 | 100 *ast.BasicLit | value : untyped int = 100 | constant
019: 20: 9 | a *ast.Ident | var : *main.foo | variable
020: 20: 9 | a.mul *ast.SelectorExpr | value : func(b *main.foo) *main.foo | value
021: 20: 9 | a.mul(c) *ast.CallExpr | value : *main.foo | value
022: 20:15 | c *ast.Ident | var : *main.foo | variable
013: 13: 7 | foo *ast.Ident | type : main.foo | type
014: 18:10 | *foo *ast.StarExpr | type : *main.foo | type
015: 18:11 | foo *ast.Ident | type : main.foo | type
016: 19: 9 | a *ast.Ident | var : *main.foo | variable
017: 19: 9 | a.mul *ast.SelectorExpr | value : func(b int) *main.foo | value
018: 19: 9 | a.mul(100) *ast.CallExpr | value : *main.foo | value
019: 19:15 | 100 *ast.BasicLit | value : untyped int = 100 | constant
020: 20: 9 | a *ast.Ident | var : *main.foo | variable
021: 20: 9 | a.mul *ast.SelectorExpr | value : func(b *main.foo) *main.foo | value
022: 20: 9 | a.mul(c) *ast.CallExpr | value : *main.foo | value
023: 20:15 | c *ast.Ident | var : *main.foo | variable
== defs ==
000: 0: 0 | Gopo_foo_mul | const main.Gopo_foo_mul untyped string
001: 2: 6 | foo | type main.foo struct{}
Expand Down
Loading