diff options
author | Matthew Dempsky <mdempsky@google.com> | 2021-06-14 19:21:14 -0700 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2021-06-16 17:32:49 +0000 |
commit | 132ea56d292eac0226eef4bc32d784b0300c3bce (patch) | |
tree | b3158a88a1ccfe5e1bed716e952e318b81294e9c /src/cmd/compile/internal/reflectdata/reflect.go | |
parent | 8f95eaddd334e61b1832628741b97462ddc84975 (diff) | |
download | go-132ea56d292eac0226eef4bc32d784b0300c3bce.tar.gz go-132ea56d292eac0226eef4bc32d784b0300c3bce.zip |
[dev.typeparams] cmd/compile: fix crawling of embeddable types
In reflectdata, we have a hack to only apply inlining for (*T).M
wrappers generated around T.M. This was a hack because I didn't
understand at the time why other cases were failing.
But I understand now: during export, we generally skip exporting the
inline bodies for unexported methods (unless they're reachable through
some other exported method). But it doesn't take into account that
embedding a type requires generating wrappers for promoted methods,
including imported, unexported methods.
For example:
package a
type T struct{}
func (T) m() {} // previously omitted by exported
package b
import "./a"
type U struct { a.T } // needs U.m -> T.m wrapper
This CL adds extra logic to the crawler to recognize that T is an
exported type directly reachable by the user, so *all* of its methods
need to be re-exported.
This finally allows simplifying reflectdata.methodWrapper to always
call inline.InlineCalls.
Change-Id: I25031d41fd6b6cd69d31c6a864b5329cdb5780e2
Reviewed-on: https://go-review.googlesource.com/c/go/+/327872
Trust: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/cmd/compile/internal/reflectdata/reflect.go')
-rw-r--r-- | src/cmd/compile/internal/reflectdata/reflect.go | 41 |
1 files changed, 26 insertions, 15 deletions
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index 5516f707fa..f4a0619935 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1795,20 +1795,24 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy return lsym } - // Only generate (*T).M wrappers for T.M in T's own package, except for - // instantiated methods. - if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && - rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg && - !rcvr.Elem().IsFullyInstantiated() { - return lsym + // imported reports whether typ is a defined type that was declared + // in an imported package, and therefore must have been compiled in + // that package. + importedType := func(typ *types.Type) bool { + return typ.Sym() != nil && typ.Sym().Pkg != types.LocalPkg && + + // Exception: need wrapper for error.Error (#29304). + // TODO(mdempsky): Put this in package runtime, like we do for + // the type descriptors for predeclared types. + typ != types.ErrorType && + + // Exception: parameterized types may have been instantiated + // with new type arguments, so we don't assume they've been + // compiled before. + !typ.IsFullyInstantiated() } - // Only generate I.M wrappers for I in I's own package - // but keep doing it for error.Error (was issue #29304) - // and methods of instantiated interfaces. - if rcvr.IsInterface() && rcvr != types.ErrorType && - rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && - !rcvr.IsFullyInstantiated() { + if importedType(rcvr) || rcvr.IsPtr() && importedType(rcvr.Elem()) { return lsym } @@ -1922,9 +1926,16 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy ir.CurFunc = fn typecheck.Stmts(fn.Body) - // Inline calls within (*T).M wrappers. This is safe because we only - // generate those wrappers within the same compilation unit as (T).M. - // TODO(mdempsky): Investigate why we can't enable this more generally. + // TODO(mdempsky): Make this unconditional. The exporter now + // includes all of the inline bodies we need, and the "importedType" + // logic above now correctly suppresses compiling out-of-package + // types that we might not have inline bodies for. The only problem + // now is that the extra inlining can now introduce further new + // itabs, and gc.dumpdata's ad hoc compile loop doesn't handle this. + // + // CL 327871 will address this by writing itabs and generating + // wrappers as part of the loop, so we won't have to worry about + // "itabs changed after compile functions loop" errors anymore. if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil { inline.InlineCalls(fn) } |