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
1 change: 1 addition & 0 deletions build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func TestBuild(t *testing.T) {
"math.go",
"oldgo/",
"print.go",
"promoted.go",
"reflect.go",
"signal.go",
"signalnotify.go",
Expand Down
35 changes: 29 additions & 6 deletions compiler/symbol.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,14 +365,37 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {

func (c *compilerContext) canonicalFunctionName(f *ssa.Function) string {
typeArgs := f.TypeArgs()
if len(typeArgs) == 0 {
return f.RelString(nil)
name := f.RelString(nil)
if len(typeArgs) != 0 {
parts := make([]string, len(typeArgs))
for i, ta := range typeArgs {
parts[i], _ = c.getTypeCodeName(ta)
}
name = f.Origin().RelString(nil) + "[" + strings.Join(parts, ",") + "]"
}
return name + methodPackageQualifier(f)
}

// methodPackageQualifier adds the declaring package to an unexported method
// promoted from another package, since RelString names it like the type's own.
func methodPackageQualifier(f *ssa.Function) string {
recv := f.Signature.Recv()
if recv == nil {
return ""
}
obj, ok := f.Object().(*types.Func)
if !ok || obj == nil || obj.Exported() || obj.Pkg() == nil {
return ""
}
t := recv.Type()
if ptr, ok := t.(*types.Pointer); ok {
t = ptr.Elem()
}
parts := make([]string, len(typeArgs))
for i, ta := range typeArgs {
parts[i], _ = c.getTypeCodeName(ta)
named, ok := types.Unalias(t).(*types.Named)
if !ok || named.Obj().Pkg() == nil || named.Obj().Pkg().Path() == obj.Pkg().Path() {
return ""
}
return f.Origin().RelString(nil) + "[" + strings.Join(parts, ",") + "]"
return "$" + obj.Pkg().Path()
}

// parsePragmas is used by getFunctionInfo to parse function pragmas such as
Expand Down
65 changes: 65 additions & 0 deletions testdata/promoted.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package main

import (
"github.com/tinygo-org/tinygo/testdata/promoted/inner"
"github.com/tinygo-org/tinygo/testdata/promoted/inner2"
)

// Outer has its own unexported methods and also the ones promoted from
// inner.Inner, which Go treats as different methods.
type Outer struct {
inner.Inner
}

func (Outer) value() int { return 2 }

func (*Outer) ptr() int { return 2 }

type PtrOuter struct {
*inner.Inner
}

func (PtrOuter) value() int { return 2 }

func (PtrOuter) ptr() int { return 2 }

type Outer2 struct {
Outer
}

type Both struct {
inner.Inner
inner2.Inner2
}

type G[T any] struct {
inner.Inner
v T
}

func (G[T]) value() int { return 2 }

type mainValuer interface{ value() int }

func main() {
println("own:", Outer{}.value())
println("promoted:", inner.Value(Outer{}))
println("own ptr:", (&Outer{}).ptr())
println("promoted ptr:", inner.Ptr(&Outer{}))

po := PtrOuter{&inner.Inner{}}
println("embedded ptr own:", po.value())
println("embedded ptr promoted:", inner.Value(po))
println("embedded ptr promoted ptr:", inner.Ptr(po))

println("two levels main:", any(Outer2{}).(mainValuer).value())
println("two levels inner:", inner.Value(Outer2{}))
println("two levels inner ptr:", inner.Ptr(&Outer2{}))

println("both inner:", inner.Value(Both{}))
println("both inner2:", inner2.Value(Both{}))

println("generic own:", G[int]{}.value())
println("generic promoted:", inner.Value(G[int]{}))
println("generic string promoted:", inner.Value(G[string]{}))
}
15 changes: 15 additions & 0 deletions testdata/promoted.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
own: 2
promoted: 1
own ptr: 2
promoted ptr: 1
embedded ptr own: 2
embedded ptr promoted: 1
embedded ptr promoted ptr: 1
two levels main: 2
two levels inner: 1
two levels inner ptr: 1
both inner: 1
both inner2: 3
generic own: 2
generic promoted: 1
generic string promoted: 1
17 changes: 17 additions & 0 deletions testdata/promoted/inner/inner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package inner

type Inner struct{}

func (Inner) value() int { return 1 }

func (*Inner) ptr() int { return 1 }

type valuer interface{ value() int }

type ptrer interface{ ptr() int }

// Value calls the value method of package inner through an interface.
func Value(v any) int { return v.(valuer).value() }

// Ptr calls the pointer method of package inner through an interface.
func Ptr(v any) int { return v.(ptrer).ptr() }
9 changes: 9 additions & 0 deletions testdata/promoted/inner2/inner2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package inner2

type Inner2 struct{}

func (Inner2) value() int { return 3 }

type valuer interface{ value() int }

func Value(v any) int { return v.(valuer).value() }
Loading