diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index a8d911f003..27e6188ab7 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -365,13 +365,6 @@ func methods(t *types.Type) []*typeSig { // imethods returns the methods of the interface type t, sorted by name. func imethods(t *types.Type) []*typeSig { - if t.HasShape() && !t.IsInterface() { - // Non-interface shape types have no methods. (There are - // corresponding functions (created by getInstantiation) that take - // the dictionary and the receiver of shape type as the first two - // arguments.) - return nil - } var methods []*typeSig for _, f := range t.AllMethods().Slice() { if f.Type.Kind() != types.TFUNC || f.Sym == nil { @@ -1804,19 +1797,13 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // We don't need a dictionary if we are reaching a method (possibly via an // embedded field) which is an interface method. if !types.IsInterfaceMethod(method.Type) { - rcvr1 := rcvr - if rcvr1.IsPtr() { - rcvr1 = rcvr.Elem() - } + rcvr1 := deref(rcvr) if len(rcvr1.RParams()) > 0 { // If rcvr has rparams, remember method as generic, which // means we need to add a dictionary to the wrapper. generic = true - targs := rcvr1.RParams() - for _, t := range targs { - if t.HasShape() { - base.Fatalf("method on type instantiated with shapes targ:%+v rcvr:%+v", t, rcvr) - } + if rcvr.HasShape() { + base.Fatalf("method on type instantiated with shapes, rcvr:%+v", rcvr) } } } @@ -1833,9 +1820,10 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy return lsym } + methodrcvr := method.Type.Recv().Type // For generic methods, we need to generate the wrapper even if the receiver // types are identical, because we want to add the dictionary. - if !generic && types.Identical(rcvr, method.Type.Recv().Type) { + if !generic && types.Identical(rcvr, methodrcvr) { return lsym } @@ -1859,7 +1847,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy nthis := ir.AsNode(tfn.Type().Recv().Nname) - methodrcvr := method.Type.Recv().Type indirect := rcvr.IsPtr() && rcvr.Elem() == methodrcvr // generate nil pointer check for better error @@ -1880,10 +1867,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // the TOC to the appropriate value for that module. But if it returns // directly to the wrapper's caller, nothing will reset it to the correct // value for that function. - // - // Disable tailcall for RegabiArgs for now. The IR does not connect the - // arguments with the OTAILCALL node, and the arguments are not marshaled - // correctly. if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !generic { call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil) call.Args = ir.ParamNames(tfn.Type()) @@ -1894,30 +1877,26 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy var call *ir.CallExpr if generic && dot.X != nthis { - // TODO: for now, we don't try to generate dictionary wrappers for - // any methods involving embedded fields, because we're not - // generating the needed dictionaries in instantiateMethods. + // If there is embedding involved, then we should do the + // normal non-generic embedding wrapper below, which calls + // the wrapper for the real receiver type using dot as an + // argument. There is no need for generic processing (adding + // a dictionary) for this wrapper. generic = false } if generic { - var args []ir.Node - var targs []*types.Type - if rcvr.IsPtr() { - targs = rcvr.Elem().RParams() - } else { - targs = rcvr.RParams() - } + targs := deref(rcvr).RParams() // The wrapper for an auto-generated pointer/non-pointer // receiver method should share the same dictionary as the // corresponding original (user-written) method. baseOrig := orig - if baseOrig.IsPtr() && !method.Type.Recv().Type.IsPtr() { + if baseOrig.IsPtr() && !methodrcvr.IsPtr() { baseOrig = baseOrig.Elem() - } else if !baseOrig.IsPtr() && method.Type.Recv().Type.IsPtr() { + } else if !baseOrig.IsPtr() && methodrcvr.IsPtr() { baseOrig = types.NewPtr(baseOrig) } - args = append(args, getDictionary(ir.MethodSym(baseOrig, method.Sym), targs)) + args := []ir.Node{getDictionary(ir.MethodSym(baseOrig, method.Sym), targs)} if indirect { args = append(args, ir.NewStarExpr(base.Pos, dot.X)) } else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() { @@ -2052,7 +2031,7 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node { sym := typecheck.MakeDictSym(gf, targs, true) - // Initialize the dictionary, if we haven't yet already. + // Dictionary should already have been generated by instantiateMethods(). if lsym := sym.Linksym(); len(lsym.P) == 0 { base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name) } @@ -2078,3 +2057,10 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node { np.SetTypecheck(1) return np } + +func deref(t *types.Type) *types.Type { + if t.IsPtr() { + return t.Elem() + } + return t +}