cmd/compile: split exported/non-exported methods for interface type

Currently, mhdr/methods is emitted with the same len/cap. There's no way
to distinguish between exported and non-exported methods statically.

This CL splits mhdr/methods into two parts, use "len" for number of
exported methods, and "cap" for all methods. This fixes the bug in
issue #22075, which intends to return the number of exported methods but
currently return all methods.

Note that with this encoding, we still can access either
all/exported-only/non-exported-only methods:

	mhdr[:cap(mhdr)]          // all methods
	mhdr                      // exported methods
	mhdr[len(mhdr):cap(mhdr)] // non-exported methods

Thank to Matthew Dempsky (@mdempsky) for suggesting this encoding.

Fixes #22075

Change-Id: If662adb03ccff27407d55a5578a0ed05a15e7cdd
Reviewed-on: https://go-review.googlesource.com/c/go/+/259237
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Cuong Manh Le 2020-10-03 01:23:47 +07:00 committed by Cuong Manh Le
parent f8df205e74
commit 8f26b57f9a
11 changed files with 124 additions and 64 deletions

View file

@ -2995,6 +2995,14 @@ func TestUnexportedMethods(t *testing.T) {
if got := typ.NumMethod(); got != 0 {
t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
}
var i unexpI
if got := TypeOf(&i).Elem().NumMethod(); got != 0 {
t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
}
if got := ValueOf(&i).Elem().NumMethod(); got != 0 {
t.Errorf("NumMethod=%d, want 0 satisfied methods", got)
}
}
type InnerInt struct {
@ -3648,21 +3656,21 @@ func TestCallPanic(t *testing.T) {
v := ValueOf(T{i, i, i, i, T2{i, i}, i, i, T2{i, i}})
badCall(func() { call(v.Field(0).Method(0)) }) // .t0.W
badCall(func() { call(v.Field(0).Elem().Method(0)) }) // .t0.W
badCall(func() { call(v.Field(0).Method(1)) }) // .t0.w
badMethod(func() { call(v.Field(0).Method(1)) }) // .t0.w
badMethod(func() { call(v.Field(0).Elem().Method(2)) }) // .t0.w
ok(func() { call(v.Field(1).Method(0)) }) // .T1.Y
ok(func() { call(v.Field(1).Elem().Method(0)) }) // .T1.Y
badCall(func() { call(v.Field(1).Method(1)) }) // .T1.y
badMethod(func() { call(v.Field(1).Method(1)) }) // .T1.y
badMethod(func() { call(v.Field(1).Elem().Method(2)) }) // .T1.y
ok(func() { call(v.Field(2).Method(0)) }) // .NamedT0.W
ok(func() { call(v.Field(2).Elem().Method(0)) }) // .NamedT0.W
badCall(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
badMethod(func() { call(v.Field(2).Method(1)) }) // .NamedT0.w
badMethod(func() { call(v.Field(2).Elem().Method(2)) }) // .NamedT0.w
ok(func() { call(v.Field(3).Method(0)) }) // .NamedT1.Y
ok(func() { call(v.Field(3).Elem().Method(0)) }) // .NamedT1.Y
badCall(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
badMethod(func() { call(v.Field(3).Method(1)) }) // .NamedT1.y
badMethod(func() { call(v.Field(3).Elem().Method(3)) }) // .NamedT1.y
ok(func() { call(v.Field(4).Field(0).Method(0)) }) // .NamedT2.T1.Y
@ -3672,7 +3680,7 @@ func TestCallPanic(t *testing.T) {
badCall(func() { call(v.Field(5).Method(0)) }) // .namedT0.W
badCall(func() { call(v.Field(5).Elem().Method(0)) }) // .namedT0.W
badCall(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
badMethod(func() { call(v.Field(5).Method(1)) }) // .namedT0.w
badMethod(func() { call(v.Field(5).Elem().Method(2)) }) // .namedT0.w
badCall(func() { call(v.Field(6).Method(0)) }) // .namedT1.Y