}
if usedInIface {
methods = append(methods, methodref{src: symIdx, r: i})
+ // The method descriptor is itself a type descriptor, and
+ // it can be used to reach other types, e.g. by using
+ // reflect.Type.Method(i).Type.In(j). We need to traverse
+ // its child types with UsedInIface set. (See also the
+ // comment below.)
+ rs := r.Sym()
+ if !d.ldr.AttrUsedInIface(rs) {
+ d.ldr.SetAttrUsedInIface(rs, true)
+ if d.ldr.AttrReachable(rs) {
+ d.ldr.SetAttrReachable(rs, false)
+ d.mark(rs, symIdx)
+ }
+ }
}
i += 2
continue
if *flagDumpDep {
to := d.ldr.SymName(symIdx)
if to != "" {
+ if d.ldr.AttrUsedInIface(symIdx) {
+ to += " <UsedInIface>"
+ }
from := "_"
if parent != 0 {
from = d.ldr.SymName(parent)
+ if d.ldr.AttrUsedInIface(parent) {
+ from += " <UsedInIface>"
+ }
}
fmt.Printf("%s -> %s\n", from, to)
}
{"typedesc", "", "type.main.T"},
{"ifacemethod", "", "main.T.M"},
{"ifacemethod2", "main.T.M", ""},
+ {"ifacemethod3", "main.S.M", ""},
}
for _, test := range tests {
test := test
--- /dev/null
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Like ifacemethod2.go, this tests that a method *is* live
+// if the type is "indirectly" converted to an interface
+// using reflection with a method descriptor as intermediate.
+
+package main
+
+import "reflect"
+
+type S int
+
+func (s S) M() { println("S.M") }
+
+type I interface { M() }
+
+type T float64
+
+func (t T) F(s S) {}
+
+func main() {
+ var t T
+ ft := reflect.TypeOf(t).Method(0).Type
+ at := ft.In(1)
+ v := reflect.New(at).Elem()
+ v.Interface().(I).M()
+}