Repository navigation
compiler: promoted unexported methods are named by their package - #5901
Conversation
|
Thanks for this fix @0pcom. I ran the tests on my local machine and took a good look. The following is edited from an automated review:
What do you think of this? |
|
@deadprogram Thanks for the review. I agree with all three and pushed 4b23652.
I ran the test on the host and on js/wasm under Node, plus |
The upstream review version of this fix (4b23652 on branch compiler-promoted-unexported). Use $ before the package path so that symbol names stay ASCII, reword the comment, and add a pointer receiver case to the test. For tinygo-org#5901
|
@deadprogram 4b23652 addresses all three points from your review. Could you take another look when you have a moment? |
|
Thanks for the fixes, 4b23652 looks good to me. One suggestion in if !ok || named.Obj().Pkg() == nil || named.Obj().Pkg().Path() == obj.Pkg().Path() {
return ""
}I also wrote some extra test cases and they all pass on the host with the current fix. They cover:
The patch is attached below and applies on top of 4b23652. promoted-extra-tests.patchdiff --git a/testdata/promoted.go b/testdata/promoted.go
index 5023dc18..63680b60 100644
--- a/testdata/promoted.go
+++ b/testdata/promoted.go
@@ -1,6 +1,9 @@
package main
-import "github.com/tinygo-org/tinygo/testdata/promoted/inner"
+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.
@@ -12,9 +15,51 @@ 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]{}))
}
diff --git a/testdata/promoted.txt b/testdata/promoted.txt
index 78e2c74d..5c368cc3 100644
--- a/testdata/promoted.txt
+++ b/testdata/promoted.txt
@@ -2,3 +2,14 @@ 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
diff --git a/testdata/promoted/inner2/inner2.go b/testdata/promoted/inner2/inner2.go
new file mode 100644
index 00000000..b80af036
--- /dev/null
+++ b/testdata/promoted/inner2/inner2.go
@@ -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() } |
|
Please rebase and fix the conflict in binary-size.txt. |
|
Merged dev in. The test list moved to build_test.go, so promoted.go is added there now. |
|
This branch needs to have a linear history so we can merge it. No merge commits, please. |
A type can hold two unexported methods of one name, its own and one promoted from an embedded type in another package, since Go names an unexported method by its declaring package. RelString spells both the same, so they shared one symbol: a call through the other package's interface ran the type's own method, and gvisor's tcp.Endpoint, which has beforeSave this way, was reported as redeclared. The promoted one now carries its package. Fixes tinygo-org#5845
Use $ before the package path, like the other synthetic names, so that symbol names stay ASCII. Reword the comment and add a pointer receiver case to the test.
…mbeddings Comparing *types.Package pointers relied on every package being type checked with one importer. The tests from dgryski cover embedding through a pointer, two levels, two packages with the same unexported method name, and a generic outer type.
417da5c to
bc7d24f
Compare
|
Rebased onto dev with no merge commits. |
A type can hold two unexported methods of one name, its own and one
promoted from an embedded type in another package, since Go names an
unexported method by its declaring package. RelString spells both the
same, so they shared one symbol: a call through the other package's
interface ran the type's own method, and gvisor's tcp.Endpoint, which
has beforeSave this way, was reported as redeclared. The promoted one
now carries its package.
Fixes #5845