Skip to content
Snippets Groups Projects
reader.go 107 KiB
Newer Older
  • Learn to ignore specific revisions
  • 			kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
    			*elemp, elemp = kv, &kv.Value
    		}
    
    		*elemp = wrapName(r.pos(), r.expr())
    	}
    
    
    	lit := typecheck.Expr(ir.NewCompLitExpr(pos, ir.OCOMPLIT, typ, elems))
    
    		lit := lit.(*ir.CompLitExpr)
    
    	if typ0.IsPtr() {
    		lit = typecheck.Expr(typecheck.NodAddrAt(pos, lit))
    		lit.SetType(typ0)
    
    	}
    	return lit
    }
    
    func wrapName(pos src.XPos, x ir.Node) ir.Node {
    	// These nodes do not carry line numbers.
    	// Introduce a wrapper node to give them the correct line.
    	switch ir.Orig(x).Op() {
    	case ir.OTYPE, ir.OLITERAL:
    		if x.Sym() == nil {
    			break
    		}
    		fallthrough
    
    	case ir.ONAME, ir.ONONAME, ir.ONIL:
    
    		p := ir.NewParenExpr(pos, x)
    		p.SetImplicit(true)
    		return p
    	}
    	return x
    }
    
    func (r *reader) funcLit() ir.Node {
    
    	r.Sync(pkgbits.SyncFuncLit)
    
    	// The underlying function declaration (including its parameters'
    	// positions, if any) need to remain the original, uninlined
    	// positions. This is because we track inlining-context on nodes so
    	// we can synthesize the extra implied stack frames dynamically when
    	// generating tracebacks, whereas those stack frames don't make
    	// sense *within* the function literal. (Any necessary inlining
    	// adjustments will have been applied to the call expression
    	// instead.)
    	//
    	// This is subtle, and getting it wrong leads to cycles in the
    	// inlining tree, which lead to infinite loops during stack
    	// unwinding (#46234, #54625).
    	//
    	// Note that we *do* want the inline-adjusted position for the
    	// OCLOSURE node, because that position represents where any heap
    	// allocation of the closure is credited (#49171).
    	r.suppressInlPos++
    
    	pos := r.pos()
    	xtype2 := r.signature(types.LocalPkg, nil)
    
    	fn := ir.NewClosureFunc(pos, r.curfn != nil)
    
    	clo.SetPos(r.inlPos(pos)) // see comment above
    
    	setType(fn.Nname, xtype2)
    
    	fn.ClosureVars = make([]*ir.Name, 0, r.Len())
    
    	for len(fn.ClosureVars) < cap(fn.ClosureVars) {
    
    		ir.NewClosureVar(r.pos(), fn, r.useLocal())
    
    	if param := r.dictParam; param != nil {
    		// If we have a dictionary parameter, capture it too. For
    		// simplicity, we capture it last and unconditionally.
    		ir.NewClosureVar(param.Pos(), fn, param)
    	}
    
    	// TODO(mdempsky): Remove hard-coding of typecheck.Target.
    	return ir.UseClosure(clo, typecheck.Target)
    
    }
    
    func (r *reader) exprList() []ir.Node {
    
    	r.Sync(pkgbits.SyncExprList)
    
    	return r.exprs()
    }
    
    func (r *reader) exprs() []ir.Node {
    
    	r.Sync(pkgbits.SyncExprs)
    	nodes := make([]ir.Node, r.Len())
    
    	if len(nodes) == 0 {
    		return nil // TODO(mdempsky): Unclear if this matters.
    	}
    	for i := range nodes {
    		nodes[i] = r.expr()
    	}
    	return nodes
    }
    
    
    // dictWord returns an expression to return the specified
    // uintptr-typed word from the dictionary parameter.
    
    func (r *reader) dictWord(pos src.XPos, idx int) ir.Node {
    
    	base.AssertfAt(r.dictParam != nil, pos, "expected dictParam in %v", r.curfn)
    
    	return typecheck.Expr(ir.NewIndexExpr(pos, r.dictParam, ir.NewBasicLit(pos, constant.MakeInt64(int64(idx)))))
    }
    
    // rttiWord is like dictWord, but converts it to *byte (the type used
    // internally to represent *runtime._type and *runtime.itab).
    func (r *reader) rttiWord(pos src.XPos, idx int) ir.Node {
    	return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, types.NewPtr(types.Types[types.TUINT8]), r.dictWord(pos, idx)))
    
    }
    
    // rtype reads a type reference from the element bitstream, and
    // returns an expression of type *runtime._type representing that
    // type.
    
    func (r *reader) rtype(pos src.XPos) ir.Node {
    
    	_, rtype := r.rtype0(pos)
    	return rtype
    
    func (r *reader) rtype0(pos src.XPos) (typ *types.Type, rtype ir.Node) {
    	r.Sync(pkgbits.SyncRType)
    	if r.Bool() { // derived type
    		idx := r.Len()
    		info := r.dict.rtypes[idx]
    		typ = r.p.typIdx(info, r.dict, true)
    		rtype = r.rttiWord(pos, r.dict.rtypesOffset()+idx)
    		return
    
    
    	typ = r.typ()
    	rtype = reflectdata.TypePtrAt(pos, typ)
    	return
    
    // varDictIndex populates name.DictIndex if name is a derived type.
    func (r *reader) varDictIndex(name *ir.Name) {
    	if r.Bool() {
    		idx := 1 + r.dict.rtypesOffset() + r.Len()
    		if int(uint16(idx)) != idx {
    			base.FatalfAt(name.Pos(), "DictIndex overflow for %v: %v", name, idx)
    		}
    		name.DictIndex = uint16(idx)
    	}
    }
    
    
    func (r *reader) itab(pos src.XPos) (typ *types.Type, typRType ir.Node, iface *types.Type, ifaceRType ir.Node, itab ir.Node) {
    	if r.Bool() { // derived types
    		idx := r.Len()
    		info := r.dict.itabs[idx]
    		typ = r.p.typIdx(info.typ, r.dict, true)
    		typRType = r.rttiWord(pos, r.dict.itabsOffset()+3*idx)
    		iface = r.p.typIdx(info.iface, r.dict, true)
    		ifaceRType = r.rttiWord(pos, r.dict.itabsOffset()+3*idx+1)
    		itab = r.rttiWord(pos, r.dict.itabsOffset()+3*idx+2)
    		return
    	}
    
    	typ = r.typ()
    	iface = r.typ()
    	if iface.IsInterface() {
    		typRType = reflectdata.TypePtrAt(pos, typ)
    		ifaceRType = reflectdata.TypePtrAt(pos, iface)
    		if !typ.IsInterface() && !iface.IsEmptyInterface() {
    			lsym := reflectdata.ITabLsym(typ, iface)
    			itab = typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8])
    		}
    	}
    	return
    
    // convRTTI returns expressions appropriate for populating an
    // ir.ConvExpr's TypeWord and SrcRType fields, respectively.
    func (r *reader) convRTTI(pos src.XPos) (typeWord, srcRType ir.Node) {
    	r.Sync(pkgbits.SyncConvRTTI)
    
    	src, srcRType0, dst, dstRType, itab := r.itab(pos)
    
    	if !dst.IsInterface() {
    		return
    	}
    
    	// See reflectdata.ConvIfaceTypeWord.
    	switch {
    	case dst.IsEmptyInterface():
    		if !src.IsInterface() {
    
    			typeWord = srcRType0 // direct eface construction
    
    		typeWord = itab // direct iface construction
    
    	}
    
    	// See reflectdata.ConvIfaceSrcRType.
    	if !src.IsInterface() {
    
    func (r *reader) exprType() ir.Node {
    
    		typ, rtype, _, _, itab = r.itab(pos)
    
    			rtype = nil // TODO(mdempsky): Leave set?
    
    		typ, rtype = r.rtype0(pos)
    
    		if !r.Bool() { // not derived
    
    			// TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node.
    			n := ir.TypeNode(typ)
    			n.SetTypecheck(1)
    			return n
    
    	dt := ir.NewDynamicType(pos, rtype)
    	dt.ITab = itab
    	return typed(typ, dt)
    
    func (r *reader) op() ir.Op {
    
    	r.Sync(pkgbits.SyncOp)
    	return ir.Op(r.Len())
    
    }
    
    // @@@ Package initialization
    
    func (r *reader) pkgInit(self *types.Pkg, target *ir.Package) {
    
    	cgoPragmas := make([][]string, r.Len())
    
    	for i := range cgoPragmas {
    
    		cgoPragmas[i] = r.Strings()
    
    	}
    	target.CgoPragmas = cgoPragmas
    
    	r.pkgDecls(target)
    
    
    }
    
    func (r *reader) pkgDecls(target *ir.Package) {
    
    		switch code := codeDecl(r.Code(pkgbits.SyncDecl)); code {
    
    		default:
    			panic(fmt.Sprintf("unhandled decl: %v", code))
    
    		case declEnd:
    			return
    
    		case declFunc:
    			names := r.pkgObjs(target)
    			assert(len(names) == 1)
    			target.Decls = append(target.Decls, names[0].Func)
    
    		case declMethod:
    			typ := r.typ()
    			_, sym := r.selector()
    
    			method := typecheck.Lookdot1(nil, sym, typ, typ.Methods(), 0)
    			target.Decls = append(target.Decls, method.Nname.(*ir.Name).Func)
    
    		case declVar:
    			pos := r.pos()
    			names := r.pkgObjs(target)
    			values := r.exprList()
    
    			if len(names) > 1 && len(values) == 1 {
    				as := ir.NewAssignListStmt(pos, ir.OAS2, nil, values)
    				for _, name := range names {
    					as.Lhs.Append(name)
    					name.Defn = as
    				}
    				target.Decls = append(target.Decls, as)
    			} else {
    				for i, name := range names {
    					as := ir.NewAssignStmt(pos, name, nil)
    					if i < len(values) {
    						as.Y = values[i]
    					}
    					name.Defn = as
    					target.Decls = append(target.Decls, as)
    				}
    			}
    
    
    				assert(len(names) == 1)
    				embeds := make([]ir.Embed, n)
    				for i := range embeds {
    
    					embeds[i] = ir.Embed{Pos: r.pos(), Patterns: r.Strings()}
    
    				}
    				names[0].Embed = &embeds
    				target.Embeds = append(target.Embeds, names[0])
    			}
    
    		case declOther:
    			r.pkgObjs(target)
    		}
    	}
    }
    
    func (r *reader) pkgObjs(target *ir.Package) []*ir.Name {
    
    	r.Sync(pkgbits.SyncDeclNames)
    	nodes := make([]*ir.Name, r.Len())
    
    		r.Sync(pkgbits.SyncDeclName)
    
    
    		name := r.obj().(*ir.Name)
    		nodes[i] = name
    
    		sym := name.Sym()
    		if sym.IsBlank() {
    			continue
    		}
    
    		switch name.Class {
    		default:
    			base.FatalfAt(name.Pos(), "unexpected class: %v", name.Class)
    
    		case ir.PEXTERN:
    			target.Externs = append(target.Externs, name)
    
    		case ir.PFUNC:
    			assert(name.Type().Recv() == nil)
    
    			// TODO(mdempsky): Cleaner way to recognize init?
    			if strings.HasPrefix(sym.Name, "init.") {
    				target.Inits = append(target.Inits, name.Func)
    			}
    		}
    
    		if types.IsExported(sym.Name) {
    			assert(!sym.OnExportList())
    			target.Exports = append(target.Exports, name)
    			sym.SetOnExportList(true)
    		}
    
    		if base.Flag.AsmHdr != "" {
    			assert(!sym.Asm())
    			target.Asms = append(target.Asms, name)
    			sym.SetAsm(true)
    		}
    	}
    
    	return nodes
    }
    
    // @@@ Inlining
    
    var inlgen = 0
    
    
    // InlineCall implements inline.NewInline by re-reading the function
    // body from its Unified IR export data.
    
    func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr {
    	// TODO(mdempsky): Turn callerfn into an explicit parameter.
    	callerfn := ir.CurFunc
    
    
    		// TODO(mdempsky): Reconsider this diagnostic's wording, if it's
    		// to be included in Go 1.20.
    		if base.Flag.LowerM != 0 {
    			base.WarnfAt(call.Pos(), "cannot inline call to %v: missing inline body", fn)
    		}
    		return nil
    
    	r := pri.asReader(pkgbits.RelocBody, pkgbits.SyncFuncBody)
    
    
    	// TODO(mdempsky): This still feels clumsy. Can we do better?
    	tmpfn := ir.NewFunc(fn.Pos())
    	tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), callerfn.Sym())
    	tmpfn.Closgen = callerfn.Closgen
    	defer func() { callerfn.Closgen = tmpfn.Closgen }()
    
    
    	setType(tmpfn.Nname, fn.Type())
    
    	r.inlCall = call
    	r.inlFunc = fn
    	r.inlTreeIndex = inlIndex
    	r.inlPosBases = make(map[*src.PosBase]*src.PosBase)
    
    
    	r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars))
    	for i, cv := range r.inlFunc.ClosureVars {
    		r.closureVars[i] = cv.Outer
    
    	if len(r.closureVars) != 0 && r.hasTypeParams() {
    		r.dictParam = r.closureVars[len(r.closureVars)-1] // dictParam is last; see reader.funcLit
    	}
    
    
    	r.funcargs(fn)
    
    	r.delayResults = fn.Inl.CanDelayResults
    
    	r.retlabel = typecheck.AutoLabel(".i")
    	inlgen++
    
    	init := ir.TakeInit(call)
    
    	// For normal function calls, the function callee expression
    
    	// may contain side effects. Make sure to preserve these,
    
    	// if necessary (#42703).
    	if call.Op() == ir.OCALLFUNC {
    
    		inline.CalleeEffects(&init, call.X)
    
    	}
    
    	var args ir.Nodes
    	if call.Op() == ir.OCALLMETH {
    
    		base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck")
    
    	}
    	args.Append(call.Args...)
    
    	// Create assignment to declare and initialize inlvars.
    	as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, r.inlvars, args)
    	as2.Def = true
    	var as2init ir.Nodes
    	for _, name := range r.inlvars {
    		if ir.IsBlank(name) {
    			continue
    		}
    		// TODO(mdempsky): Use inlined position of name.Pos() instead?
    		name := name.(*ir.Name)
    		as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
    		name.Defn = as2
    	}
    	as2.SetInit(as2init)
    	init.Append(typecheck.Stmt(as2))
    
    	if !r.delayResults {
    		// If not delaying retvars, declare and zero initialize the
    		// result variables now.
    		for _, name := range r.retvars {
    			// TODO(mdempsky): Use inlined position of name.Pos() instead?
    			name := name.(*ir.Name)
    			init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name))
    			ras := ir.NewAssignStmt(call.Pos(), name, nil)
    			init.Append(typecheck.Stmt(ras))
    		}
    	}
    
    	// Add an inline mark just before the inlined body.
    	// This mark is inline in the code so that it's a reasonable spot
    	// to put a breakpoint. Not sure if that's really necessary or not
    	// (in which case it could go at the end of the function instead).
    	// Note issue 28603.
    	init.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(r.inlTreeIndex)))
    
    	nparams := len(r.curfn.Dcl)
    
    
    		if !r.syntheticBody(call.Pos()) {
    			assert(r.Bool()) // have body
    
    
    			r.curfn.Body = r.stmts()
    			r.curfn.Endlineno = r.pos()
    		}
    
    		// TODO(mdempsky): This shouldn't be necessary. Inlining might
    		// read in new function/method declarations, which could
    		// potentially be recursively inlined themselves; but we shouldn't
    		// need to read in the non-inlined bodies for the declarations
    		// themselves. But currently it's an easy fix to #50552.
    		readBodies(typecheck.Target)
    
    
    		// Replace any "return" statements within the function body.
    
    		var edit func(ir.Node) ir.Node
    		edit = func(n ir.Node) ir.Node {
    			if ret, ok := n.(*ir.ReturnStmt); ok {
    				n = typecheck.Stmt(r.inlReturn(ret))
    			}
    			ir.EditChildren(n, edit)
    			return n
    		}
    		edit(r.curfn)
    
    
    	body := ir.Nodes(r.curfn.Body)
    
    	// Quirkish: We need to eagerly prune variables added during
    	// inlining, but removed by deadcode.FuncBody above. Unused
    	// variables will get removed during stack frame layout anyway, but
    	// len(fn.Dcl) ends up influencing things like autotmp naming.
    
    	used := usedLocals(body)
    
    	for i, name := range r.curfn.Dcl {
    		if i < nparams || used.Has(name) {
    			name.Curfn = callerfn
    			callerfn.Dcl = append(callerfn.Dcl, name)
    
    			// Quirkish. TODO(mdempsky): Document why.
    			if name.AutoTemp() {
    				name.SetEsc(ir.EscUnknown)
    
    				if base.Flag.GenDwarfInl != 0 {
    					name.SetInlLocal(true)
    				} else {
    					name.SetPos(r.inlCall.Pos())
    				}
    			}
    		}
    	}
    
    	body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel))
    
    	res := ir.NewInlinedCallExpr(call.Pos(), body, append([]ir.Node(nil), r.retvars...))
    	res.SetInit(init)
    	res.SetType(call.Type())
    	res.SetTypecheck(1)
    
    	// Inlining shouldn't add any functions to todoBodies.
    	assert(len(todoBodies) == 0)
    
    	return res
    }
    
    // inlReturn returns a statement that can substitute for the given
    // return statement when inlining.
    func (r *reader) inlReturn(ret *ir.ReturnStmt) *ir.BlockStmt {
    	pos := r.inlCall.Pos()
    
    	block := ir.TakeInit(ret)
    
    	if results := ret.Results; len(results) != 0 {
    		assert(len(r.retvars) == len(results))
    
    		as2 := ir.NewAssignListStmt(pos, ir.OAS2, append([]ir.Node(nil), r.retvars...), ret.Results)
    
    		if r.delayResults {
    			for _, name := range r.retvars {
    				// TODO(mdempsky): Use inlined position of name.Pos() instead?
    				name := name.(*ir.Name)
    				block.Append(ir.NewDecl(pos, ir.ODCL, name))
    				name.Defn = as2
    			}
    		}
    
    		block.Append(as2)
    	}
    
    	block.Append(ir.NewBranchStmt(pos, ir.OGOTO, r.retlabel))
    	return ir.NewBlockStmt(pos, block)
    }
    
    // expandInline reads in an extra copy of IR to populate
    // fn.Inl.{Dcl,Body}.
    func expandInline(fn *ir.Func, pri pkgReaderIndex) {
    
    	// TODO(mdempsky): Remove this function. It's currently needed by
    	// dwarfgen/dwarf.go:preInliningDcls, which requires fn.Inl.Dcl to
    	// create abstract function DIEs. But we should be able to provide it
    
    	// with the same information some other way.
    
    	fndcls := len(fn.Dcl)
    	topdcls := len(typecheck.Target.Decls)
    
    	tmpfn := ir.NewFunc(fn.Pos())
    	tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), fn.Sym())
    	tmpfn.ClosureVars = fn.ClosureVars
    
    	{
    
    		r := pri.asReader(pkgbits.RelocBody, pkgbits.SyncFuncBody)
    
    		setType(tmpfn.Nname, fn.Type())
    
    
    		// Don't change parameter's Sym/Nname fields.
    		r.funarghack = true
    
    		r.funcBody(tmpfn)
    
    
    		ir.WithFunc(tmpfn, func() {
    			deadcode.Func(tmpfn)
    		})
    	}
    
    
    	used := usedLocals(tmpfn.Body)
    
    	for _, name := range tmpfn.Dcl {
    		if name.Class != ir.PAUTO || used.Has(name) {
    			name.Curfn = fn
    			fn.Inl.Dcl = append(fn.Inl.Dcl, name)
    		}
    	}
    	fn.Inl.Body = tmpfn.Body
    
    	// Double check that we didn't change fn.Dcl by accident.
    	assert(fndcls == len(fn.Dcl))
    
    	// typecheck.Stmts may have added function literals to
    	// typecheck.Target.Decls. Remove them again so we don't risk trying
    	// to compile them multiple times.
    	typecheck.Target.Decls = typecheck.Target.Decls[:topdcls]
    }
    
    // usedLocals returns a set of local variables that are used within body.
    func usedLocals(body []ir.Node) ir.NameSet {
    	var used ir.NameSet
    	ir.VisitList(body, func(n ir.Node) {
    		if n, ok := n.(*ir.Name); ok && n.Op() == ir.ONAME && n.Class == ir.PAUTO {
    			used.Add(n)
    		}
    	})
    	return used
    }
    
    
    // @@@ Method wrappers
    
    // needWrapperTypes lists types for which we may need to generate
    // method wrappers.
    var needWrapperTypes []*types.Type
    
    
    // haveWrapperTypes lists types for which we know we already have
    // method wrappers, because we found the type in an imported package.
    var haveWrapperTypes []*types.Type
    
    // needMethodValueWrappers lists methods for which we may need to
    // generate method value wrappers.
    var needMethodValueWrappers []methodValueWrapper
    
    // haveMethodValueWrappers lists methods for which we know we already
    // have method value wrappers, because we found it in an imported
    // package.
    var haveMethodValueWrappers []methodValueWrapper
    
    type methodValueWrapper struct {
    	rcvr   *types.Type
    	method *types.Field
    }
    
    func (r *reader) needWrapper(typ *types.Type) {
    
    		return
    	}
    
    	// If a type was found in an imported package, then we can assume
    	// that package (or one of its transitive dependencies) already
    	// generated method wrappers for it.
    	if r.importedDef() {
    		haveWrapperTypes = append(haveWrapperTypes, typ)
    	} else {
    		needWrapperTypes = append(needWrapperTypes, typ)
    
    // importedDef reports whether r is reading from an imported and
    // non-generic element.
    //
    // If a type was found in an imported package, then we can assume that
    // package (or one of its transitive dependencies) already generated
    // method wrappers for it.
    //
    // Exception: If we're instantiating an imported generic type or
    // function, we might be instantiating it with type arguments not
    // previously seen before.
    //
    // TODO(mdempsky): Distinguish when a generic function or type was
    // instantiated in an imported package so that we can add types to
    // haveWrapperTypes instead.
    
    func (r *reader) importedDef() bool {
    	return r.p != localPkgReader && !r.hasTypeParams()
    
    func MakeWrappers(target *ir.Package) {
    
    	// Only unified IR emits its own wrappers.
    	if base.Debug.Unified == 0 {
    
    	// always generate a wrapper for error.Error (#29304)
    
    	needWrapperTypes = append(needWrapperTypes, types.ErrorType)
    
    		wrapType(typ, target, seen, false)
    
    	}
    	haveWrapperTypes = nil
    
    	for _, typ := range needWrapperTypes {
    
    		wrapType(typ, target, seen, true)
    
    
    	for _, wrapper := range haveMethodValueWrappers {
    
    		wrapMethodValue(wrapper.rcvr, wrapper.method, target, false)
    
    	}
    	haveMethodValueWrappers = nil
    
    	for _, wrapper := range needMethodValueWrappers {
    
    		wrapMethodValue(wrapper.rcvr, wrapper.method, target, true)
    
    func wrapType(typ *types.Type, target *ir.Package, seen map[string]*types.Type, needed bool) {
    
    	key := typ.LinkString()
    	if prev := seen[key]; prev != nil {
    		if !types.Identical(typ, prev) {
    			base.Fatalf("collision: types %v and %v have link string %q", typ, prev, key)
    		}
    		return
    	}
    	seen[key] = typ
    
    	if !needed {
    		// Only called to add to 'seen'.
    		return
    	}
    
    
    	if !typ.IsInterface() {
    		typecheck.CalcMethods(typ)
    	}
    	for _, meth := range typ.AllMethods().Slice() {
    		if meth.Sym.IsBlank() || !meth.IsMethod() {
    			base.FatalfAt(meth.Pos, "invalid method: %v", meth)
    		}
    
    
    		methodWrapper(0, typ, meth, target)
    
    
    		// For non-interface types, we also want *T wrappers.
    		if !typ.IsInterface() {
    
    			methodWrapper(1, typ, meth, target)
    
    
    			// For not-in-heap types, *T is a scalar, not pointer shaped,
    			// so the interface wrappers use **T.
    			if typ.NotInHeap() {
    
    				methodWrapper(2, typ, meth, target)
    
    func methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) {
    
    	wrapper := tbase
    	for i := 0; i < derefs; i++ {
    		wrapper = types.NewPtr(wrapper)
    	}
    
    	sym := ir.MethodSym(wrapper, method.Sym)
    
    	base.Assertf(!sym.Siggen(), "already generated wrapper %v", sym)
    
    	sym.SetSiggen(true)
    
    	wrappee := method.Type.Recv().Type
    	if types.Identical(wrapper, wrappee) ||
    		!types.IsMethodApplicable(wrapper, method) ||
    		!reflectdata.NeedEmit(tbase) {
    		return
    	}
    
    	// TODO(mdempsky): Use method.Pos instead?
    	pos := base.AutogeneratedPos
    
    
    	fn := newWrapperFunc(pos, sym, wrapper, method)
    
    
    	var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name)
    
    	// For simple *T wrappers around T methods, panicwrap produces a
    	// nicer panic message.
    	if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) {
    		cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node))
    		then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)}
    		fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil))
    	}
    
    	// typecheck will add one implicit deref, if necessary,
    	// but not-in-heap types require more for their **T wrappers.
    	for i := 1; i < derefs; i++ {
    		recv = Implicit(ir.NewStarExpr(pos, recv))
    	}
    
    	addTailCall(pos, fn, recv, method)
    
    	finishWrapperFunc(fn, target)
    
    func wrapMethodValue(recvType *types.Type, method *types.Field, target *ir.Package, needed bool) {
    
    	sym := ir.MethodSymSuffix(recvType, method.Sym, "-fm")
    
    	sym.SetUniq(true)
    
    	// TODO(mdempsky): Use method.Pos instead?
    	pos := base.AutogeneratedPos
    
    
    	fn := newWrapperFunc(pos, sym, nil, method)
    
    
    	// Declare and initialize variable holding receiver.
    
    	recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType)
    
    	finishWrapperFunc(fn, target)
    
    func newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func {
    
    	fn.SetDupok(true) // TODO(mdempsky): Leave unset for local, non-generic wrappers?
    
    	name := ir.NewNameAt(pos, sym)
    	ir.MarkFunc(name)
    	name.Func = fn
    	name.Defn = fn
    	fn.Nname = name
    
    	sig := newWrapperType(wrapper, method)
    
    
    	// TODO(mdempsky): De-duplicate with similar logic in funcargs.
    
    	defParams := func(class ir.Class, params *types.Type) {
    		for _, param := range params.FieldSlice() {
    
    			name := ir.NewNameAt(param.Pos, param.Sym)
    			name.Class = class
    
    			setType(name, param.Type)
    
    
    			name.Curfn = fn
    			fn.Dcl = append(fn.Dcl, name)
    
    			param.Nname = name
    		}
    	}
    
    
    	defParams(ir.PPARAM, sig.Recvs())
    	defParams(ir.PPARAM, sig.Params())
    	defParams(ir.PPARAMOUT, sig.Results())
    
    func finishWrapperFunc(fn *ir.Func, target *ir.Package) {
    
    	typecheck.Func(fn)
    
    	ir.WithFunc(fn, func() {
    		typecheck.Stmts(fn.Body)
    	})
    
    
    	// We generate wrappers after the global inlining pass,
    	// so we're responsible for applying inlining ourselves here.
    	inline.InlineCalls(fn)
    
    
    	// The body of wrapper function after inlining may reveal new ir.OMETHVALUE node,
    	// we don't know whether wrapper function has been generated for it or not, so
    	// generate one immediately here.
    	ir.VisitList(fn.Body, func(n ir.Node) {
    		if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE {
    			wrapMethodValue(n.X.Type(), n.Selection, target, true)
    		}
    	})
    
    
    // newWrapperType returns a copy of the given signature type, but with
    
    // the receiver parameter type substituted with recvType.
    // If recvType is nil, newWrapperType returns a signature
    // without a receiver parameter.
    func newWrapperType(recvType *types.Type, method *types.Field) *types.Type {
    
    	clone := func(params []*types.Field) []*types.Field {
    		res := make([]*types.Field, len(params))
    		for i, param := range params {
    			sym := param.Sym
    			if sym == nil || sym.Name == "_" {
    				sym = typecheck.LookupNum(".anon", i)
    			}
    			res[i] = types.NewField(param.Pos, sym, param.Type)
    			res[i].SetIsDDD(param.IsDDD())
    		}
    		return res
    	}
    
    
    	sig := method.Type
    
    	var recv *types.Field
    	if recvType != nil {
    		recv = types.NewField(sig.Recv().Pos, typecheck.Lookup(".this"), recvType)
    	}
    
    	params := clone(sig.Params().FieldSlice())
    	results := clone(sig.Results().FieldSlice())
    
    	return types.NewSignature(types.NoPkg, recv, nil, params, results)
    }
    
    
    func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) {
    	sig := fn.Nname.Type()
    	args := make([]ir.Node, sig.NumParams())
    	for i, param := range sig.Params().FieldSlice() {
    		args[i] = param.Nname.(*ir.Name)
    	}
    
    
    	// TODO(mdempsky): Support creating OTAILCALL, when possible. See reflectdata.methodWrapper.
    	// Not urgent though, because tail calls are currently incompatible with regabi anyway.
    
    
    	fn.SetWrapper(true) // TODO(mdempsky): Leave unset for tail calls?
    
    
    	dot := ir.NewSelectorExpr(pos, ir.OXDOT, recv, method.Sym)
    	call := typecheck.Call(pos, dot, args, method.Type.IsVariadic()).(*ir.CallExpr)
    
    	}
    
    	ret := ir.NewReturnStmt(pos, nil)
    	ret.Results = []ir.Node{call}
    
    
    func setBasePos(pos src.XPos) {
    	// Set the position for any error messages we might print (e.g. too large types).
    	base.Pos = pos
    }
    
    
    // dictParamName is the name of the synthetic dictionary parameter
    // added to shaped functions.
    
    //
    // N.B., this variable name is known to Delve:
    // https://github.com/go-delve/delve/blob/cb91509630529e6055be845688fd21eb89ae8714/pkg/proc/eval.go#L28
    
    const dictParamName = ".dict"
    
    // shapeSig returns a copy of fn's signature, except adding a
    // dictionary parameter and promoting the receiver parameter (if any)
    // to a normal parameter.
    //
    // The parameter types.Fields are all copied too, so their Nname
    // fields can be initialized for use by the shape function.
    func shapeSig(fn *ir.Func, dict *readerDict) *types.Type {
    	sig := fn.Nname.Type()
    
    	oldRecv := sig.Recv()
    
    	var recv *types.Field
    	if oldRecv != nil {
    		recv = types.NewField(oldRecv.Pos, oldRecv.Sym, oldRecv.Type)
    
    	params := make([]*types.Field, 1+sig.Params().Fields().Len())
    
    	params[0] = types.NewField(fn.Pos(), fn.Sym().Pkg.Lookup(dictParamName), types.NewPtr(dict.varType()))
    	for i, param := range sig.Params().Fields().Slice() {
    		d := types.NewField(param.Pos, param.Sym, param.Type)
    		d.SetIsDDD(param.IsDDD())
    
    	}
    
    	results := make([]*types.Field, sig.Results().Fields().Len())
    	for i, result := range sig.Results().Fields().Slice() {
    		results[i] = types.NewField(result.Pos, result.Sym, result.Type)
    	}
    
    
    	return types.NewSignature(types.LocalPkg, recv, nil, params, results)