Hi all, Recently, I managed to get this to work:
x := []int{1, 2, 3} x.reverse() fmt.Println(x) That is, when I run my modified compiler on this code, it prints [3, 2, 1]. Neat! To be clear, I am *not* intending to get this merged upstream -- this is just a fun exercise to learn my way around the compiler. My approach was as follows. First, I added a reverse function to the runtime package: func reverse(et *_type, s slice) { tmp := newobject(et) // swap scratch space for i := 0; i < s.len/2; i++ { j := s.len - i - 1 ei := add(s.array, uintptr(i)*et.size) ej := add(s.array, uintptr(j)*et.size) typedmemmove(et, tmp, ei) typedmemmove(et, ei, ej) typedmemmove(et, ej, tmp) } } I added this function's name to gc/builtin/runtime.go and ran go generate to update gc/builtin.go. Next, I modified the lookdot function of typecheck.go, such that when a method named "reverse" is looked for on a slice type, and no existing method is found, a sentinel method with the appropriate type is returned: if n.Left.Type == t || n.Left.Type.Sym == nil { mt := methtype(t) if mt != nil { f2 = lookdot1(n, s, mt, mt.Methods(), dostrcmp) } // new code if f2 == nil && t.IsSlice() { if s.Name == "reverse" { recv := types.NewField() recv.Type = t f2 = types.NewField() f2.Sym = &types.Sym{ Name: "reverse", Pkg: builtinpkg, } f2.Type = functypefield(recv, nil, nil) } } } Finally, I modified gc/walk.go to replace the method call with a call to the runtime function: case OCALLINTER, OCALLFUNC, OCALLMETH: if n.Op == OCALLINTER { usemethod(n) markUsedIfaceMethod(n) } // new code if n.Left != nil && n.Left.Sym.Def == nil { methname := n.Left.Sym.Name if strings.HasSuffix(methname, "reverse") { s := n.Left.Left fn := syslook("reverse") fn = substArgTypes(fn, s.Type.Elem()) n = mkcall1(fn, nil, init, typename(s.Type.Elem()), s) } } This approach works, but I feel like I'm bludgeoning a very sophisticated system into doing something it was not designed to do. I'm hoping that a more experienced compiler hacker can offer some guidance as to the "Right Way" of doing this. If you were tasked with adding a builtin method to all slices, how would you do it? In particular, how do I handle inlining? Currently I have to disable all inlining when compiling; otherwise, I get internal compiler error: no function definition. I assume this is because the inlining phase runs before the method call is replaced with a runtime call. Is it possible to hook up the method call to the runtime function definition during the typecheck phase? Relatedly, I'm finding compiler development to be much more cumbersome than the Go programming I'm accustomed to. Specifically, I'm currently re-running make.bash after each change, which takes around 4 minutes on my machine. Is it possible to test my changes without re-running make.bash, ideally compiling in just a few seconds? Another issue is that gopls does not seem to like operating on the compiler source, at least when used with VS Code. What IDE do other compiler devs use? Sorry for the barrage of questions -- I hope this is the right place to ask them! -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/ada79351-fffa-4de3-8b53-821ed0ba3ebcn%40googlegroups.com.