github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/ir/fmt.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ir
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"github.com/bir3/gocompiler/src/go/constant"
    11  	"io"
    12  	"math"
    13  	"os"
    14  	"path/filepath"
    15  	"reflect"
    16  	"strings"
    17  
    18  	"unicode/utf8"
    19  
    20  	"github.com/bir3/gocompiler/src/cmd/compile/internal/base"
    21  	"github.com/bir3/gocompiler/src/cmd/compile/internal/types"
    22  	"github.com/bir3/gocompiler/src/cmd/internal/src"
    23  )
    24  
    25  // Op
    26  
    27  var OpNames = []string{
    28  	OADDR:             "&",
    29  	OADD:              "+",
    30  	OADDSTR:           "+",
    31  	OALIGNOF:          "unsafe.Alignof",
    32  	OANDAND:           "&&",
    33  	OANDNOT:           "&^",
    34  	OAND:              "&",
    35  	OAPPEND:           "append",
    36  	OAS:               "=",
    37  	OAS2:              "=",
    38  	OBREAK:            "break",
    39  	OCALL:             "function call", // not actual syntax
    40  	OCAP:              "cap",
    41  	OCASE:             "case",
    42  	OCLOSE:            "close",
    43  	OCOMPLEX:          "complex",
    44  	OBITNOT:           "^",
    45  	OCONTINUE:         "continue",
    46  	OCOPY:             "copy",
    47  	ODELETE:           "delete",
    48  	ODEFER:            "defer",
    49  	ODIV:              "/",
    50  	OEQ:               "==",
    51  	OFALL:             "fallthrough",
    52  	OFOR:              "for",
    53  	OGE:               ">=",
    54  	OGOTO:             "goto",
    55  	OGT:               ">",
    56  	OIF:               "if",
    57  	OIMAG:             "imag",
    58  	OINLMARK:          "inlmark",
    59  	ODEREF:            "*",
    60  	OLEN:              "len",
    61  	OLE:               "<=",
    62  	OLSH:              "<<",
    63  	OLT:               "<",
    64  	OMAKE:             "make",
    65  	ONEG:              "-",
    66  	OMOD:              "%",
    67  	OMUL:              "*",
    68  	ONEW:              "new",
    69  	ONE:               "!=",
    70  	ONOT:              "!",
    71  	OOFFSETOF:         "unsafe.Offsetof",
    72  	OOROR:             "||",
    73  	OOR:               "|",
    74  	OPANIC:            "panic",
    75  	OPLUS:             "+",
    76  	OPRINTN:           "println",
    77  	OPRINT:            "print",
    78  	ORANGE:            "range",
    79  	OREAL:             "real",
    80  	ORECV:             "<-",
    81  	ORECOVER:          "recover",
    82  	ORETURN:           "return",
    83  	ORSH:              ">>",
    84  	OSELECT:           "select",
    85  	OSEND:             "<-",
    86  	OSIZEOF:           "unsafe.Sizeof",
    87  	OSUB:              "-",
    88  	OSWITCH:           "switch",
    89  	OUNSAFEADD:        "unsafe.Add",
    90  	OUNSAFESLICE:      "unsafe.Slice",
    91  	OUNSAFESLICEDATA:  "unsafe.SliceData",
    92  	OUNSAFESTRING:     "unsafe.String",
    93  	OUNSAFESTRINGDATA: "unsafe.StringData",
    94  	OXOR:              "^",
    95  }
    96  
    97  // GoString returns the Go syntax for the Op, or else its name.
    98  func (o Op) GoString() string {
    99  	if int(o) < len(OpNames) && OpNames[o] != "" {
   100  		return OpNames[o]
   101  	}
   102  	return o.String()
   103  }
   104  
   105  // Format implements formatting for an Op.
   106  // The valid formats are:
   107  //
   108  //	%v	Go syntax ("+", "<-", "print")
   109  //	%+v	Debug syntax ("ADD", "RECV", "PRINT")
   110  func (o Op) Format(s fmt.State, verb rune) {
   111  	switch verb {
   112  	default:
   113  		fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
   114  	case 'v':
   115  		if s.Flag('+') {
   116  			// %+v is OMUL instead of "*"
   117  			io.WriteString(s, o.String())
   118  			return
   119  		}
   120  		io.WriteString(s, o.GoString())
   121  	}
   122  }
   123  
   124  // Node
   125  
   126  // fmtNode implements formatting for a Node n.
   127  // Every Node implementation must define a Format method that calls fmtNode.
   128  // The valid formats are:
   129  //
   130  //	%v	Go syntax
   131  //	%L	Go syntax followed by " (type T)" if type is known.
   132  //	%+v	Debug syntax, as in Dump.
   133  func fmtNode(n Node, s fmt.State, verb rune) {
   134  	// %+v prints Dump.
   135  	// Otherwise we print Go syntax.
   136  	if s.Flag('+') && verb == 'v' {
   137  		dumpNode(s, n, 1)
   138  		return
   139  	}
   140  
   141  	if verb != 'v' && verb != 'S' && verb != 'L' {
   142  		fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
   143  		return
   144  	}
   145  
   146  	if n == nil {
   147  		fmt.Fprint(s, "<nil>")
   148  		return
   149  	}
   150  
   151  	t := n.Type()
   152  	if verb == 'L' && t != nil {
   153  		if t.Kind() == types.TNIL {
   154  			fmt.Fprint(s, "nil")
   155  		} else if n.Op() == ONAME && n.Name().AutoTemp() {
   156  			fmt.Fprintf(s, "%v value", t)
   157  		} else {
   158  			fmt.Fprintf(s, "%v (type %v)", n, t)
   159  		}
   160  		return
   161  	}
   162  
   163  	// TODO inlining produces expressions with ninits. we can't print these yet.
   164  
   165  	if OpPrec[n.Op()] < 0 {
   166  		stmtFmt(n, s)
   167  		return
   168  	}
   169  
   170  	exprFmt(n, s, 0)
   171  }
   172  
   173  var OpPrec = []int{
   174  	OALIGNOF:          8,
   175  	OAPPEND:           8,
   176  	OBYTES2STR:        8,
   177  	OARRAYLIT:         8,
   178  	OSLICELIT:         8,
   179  	ORUNES2STR:        8,
   180  	OCALLFUNC:         8,
   181  	OCALLINTER:        8,
   182  	OCALLMETH:         8,
   183  	OCALL:             8,
   184  	OCAP:              8,
   185  	OCLOSE:            8,
   186  	OCOMPLIT:          8,
   187  	OCONVIFACE:        8,
   188  	OCONVIDATA:        8,
   189  	OCONVNOP:          8,
   190  	OCONV:             8,
   191  	OCOPY:             8,
   192  	ODELETE:           8,
   193  	OGETG:             8,
   194  	OLEN:              8,
   195  	OLITERAL:          8,
   196  	OMAKESLICE:        8,
   197  	OMAKESLICECOPY:    8,
   198  	OMAKE:             8,
   199  	OMAPLIT:           8,
   200  	ONAME:             8,
   201  	ONEW:              8,
   202  	ONIL:              8,
   203  	ONONAME:           8,
   204  	OOFFSETOF:         8,
   205  	OPANIC:            8,
   206  	OPAREN:            8,
   207  	OPRINTN:           8,
   208  	OPRINT:            8,
   209  	ORUNESTR:          8,
   210  	OSIZEOF:           8,
   211  	OSLICE2ARR:        8,
   212  	OSLICE2ARRPTR:     8,
   213  	OSTR2BYTES:        8,
   214  	OSTR2RUNES:        8,
   215  	OSTRUCTLIT:        8,
   216  	OTYPE:             8,
   217  	OUNSAFEADD:        8,
   218  	OUNSAFESLICE:      8,
   219  	OUNSAFESLICEDATA:  8,
   220  	OUNSAFESTRING:     8,
   221  	OUNSAFESTRINGDATA: 8,
   222  	OINDEXMAP:         8,
   223  	OINDEX:            8,
   224  	OSLICE:            8,
   225  	OSLICESTR:         8,
   226  	OSLICEARR:         8,
   227  	OSLICE3:           8,
   228  	OSLICE3ARR:        8,
   229  	OSLICEHEADER:      8,
   230  	OSTRINGHEADER:     8,
   231  	ODOTINTER:         8,
   232  	ODOTMETH:          8,
   233  	ODOTPTR:           8,
   234  	ODOTTYPE2:         8,
   235  	ODOTTYPE:          8,
   236  	ODOT:              8,
   237  	OXDOT:             8,
   238  	OMETHVALUE:        8,
   239  	OMETHEXPR:         8,
   240  	OPLUS:             7,
   241  	ONOT:              7,
   242  	OBITNOT:           7,
   243  	ONEG:              7,
   244  	OADDR:             7,
   245  	ODEREF:            7,
   246  	ORECV:             7,
   247  	OMUL:              6,
   248  	ODIV:              6,
   249  	OMOD:              6,
   250  	OLSH:              6,
   251  	ORSH:              6,
   252  	OAND:              6,
   253  	OANDNOT:           6,
   254  	OADD:              5,
   255  	OSUB:              5,
   256  	OOR:               5,
   257  	OXOR:              5,
   258  	OEQ:               4,
   259  	OLT:               4,
   260  	OLE:               4,
   261  	OGE:               4,
   262  	OGT:               4,
   263  	ONE:               4,
   264  	OSEND:             3,
   265  	OANDAND:           2,
   266  	OOROR:             1,
   267  
   268  	// Statements handled by stmtfmt
   269  	OAS:         -1,
   270  	OAS2:        -1,
   271  	OAS2DOTTYPE: -1,
   272  	OAS2FUNC:    -1,
   273  	OAS2MAPR:    -1,
   274  	OAS2RECV:    -1,
   275  	OASOP:       -1,
   276  	OBLOCK:      -1,
   277  	OBREAK:      -1,
   278  	OCASE:       -1,
   279  	OCONTINUE:   -1,
   280  	ODCL:        -1,
   281  	ODEFER:      -1,
   282  	OFALL:       -1,
   283  	OFOR:        -1,
   284  	OGOTO:       -1,
   285  	OIF:         -1,
   286  	OLABEL:      -1,
   287  	OGO:         -1,
   288  	ORANGE:      -1,
   289  	ORETURN:     -1,
   290  	OSELECT:     -1,
   291  	OSWITCH:     -1,
   292  
   293  	OEND: 0,
   294  }
   295  
   296  // StmtWithInit reports whether op is a statement with an explicit init list.
   297  func StmtWithInit(op Op) bool {
   298  	switch op {
   299  	case OIF, OFOR, OSWITCH:
   300  		return true
   301  	}
   302  	return false
   303  }
   304  
   305  func stmtFmt(n Node, s fmt.State) {
   306  	// NOTE(rsc): This code used to support the text-based
   307  	// which was more aggressive about printing full Go syntax
   308  	// (for example, an actual loop instead of "for loop").
   309  	// The code is preserved for now in case we want to expand
   310  	// any of those shortenings later. Or maybe we will delete
   311  	// the code. But for now, keep it.
   312  	const exportFormat = false
   313  
   314  	// some statements allow for an init, but at most one,
   315  	// but we may have an arbitrary number added, eg by typecheck
   316  	// and inlining. If it doesn't fit the syntax, emit an enclosing
   317  	// block starting with the init statements.
   318  
   319  	// if we can just say "for" n->ninit; ... then do so
   320  	simpleinit := len(n.Init()) == 1 && len(n.Init()[0].Init()) == 0 && StmtWithInit(n.Op())
   321  
   322  	// otherwise, print the inits as separate statements
   323  	complexinit := len(n.Init()) != 0 && !simpleinit && exportFormat
   324  
   325  	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
   326  	extrablock := complexinit && StmtWithInit(n.Op())
   327  
   328  	if extrablock {
   329  		fmt.Fprint(s, "{")
   330  	}
   331  
   332  	if complexinit {
   333  		fmt.Fprintf(s, " %v; ", n.Init())
   334  	}
   335  
   336  	switch n.Op() {
   337  	case ODCL:
   338  		n := n.(*Decl)
   339  		fmt.Fprintf(s, "var %v %v", n.X.Sym(), n.X.Type())
   340  
   341  	// Don't export "v = <N>" initializing statements, hope they're always
   342  	// preceded by the DCL which will be re-parsed and typechecked to reproduce
   343  	// the "v = <N>" again.
   344  	case OAS:
   345  		n := n.(*AssignStmt)
   346  		if n.Def && !complexinit {
   347  			fmt.Fprintf(s, "%v := %v", n.X, n.Y)
   348  		} else {
   349  			fmt.Fprintf(s, "%v = %v", n.X, n.Y)
   350  		}
   351  
   352  	case OASOP:
   353  		n := n.(*AssignOpStmt)
   354  		if n.IncDec {
   355  			if n.AsOp == OADD {
   356  				fmt.Fprintf(s, "%v++", n.X)
   357  			} else {
   358  				fmt.Fprintf(s, "%v--", n.X)
   359  			}
   360  			break
   361  		}
   362  
   363  		fmt.Fprintf(s, "%v %v= %v", n.X, n.AsOp, n.Y)
   364  
   365  	case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
   366  		n := n.(*AssignListStmt)
   367  		if n.Def && !complexinit {
   368  			fmt.Fprintf(s, "%.v := %.v", n.Lhs, n.Rhs)
   369  		} else {
   370  			fmt.Fprintf(s, "%.v = %.v", n.Lhs, n.Rhs)
   371  		}
   372  
   373  	case OBLOCK:
   374  		n := n.(*BlockStmt)
   375  		if len(n.List) != 0 {
   376  			fmt.Fprintf(s, "%v", n.List)
   377  		}
   378  
   379  	case ORETURN:
   380  		n := n.(*ReturnStmt)
   381  		fmt.Fprintf(s, "return %.v", n.Results)
   382  
   383  	case OTAILCALL:
   384  		n := n.(*TailCallStmt)
   385  		fmt.Fprintf(s, "tailcall %v", n.Call)
   386  
   387  	case OINLMARK:
   388  		n := n.(*InlineMarkStmt)
   389  		fmt.Fprintf(s, "inlmark %d", n.Index)
   390  
   391  	case OGO:
   392  		n := n.(*GoDeferStmt)
   393  		fmt.Fprintf(s, "go %v", n.Call)
   394  
   395  	case ODEFER:
   396  		n := n.(*GoDeferStmt)
   397  		fmt.Fprintf(s, "defer %v", n.Call)
   398  
   399  	case OIF:
   400  		n := n.(*IfStmt)
   401  		if simpleinit {
   402  			fmt.Fprintf(s, "if %v; %v { %v }", n.Init()[0], n.Cond, n.Body)
   403  		} else {
   404  			fmt.Fprintf(s, "if %v { %v }", n.Cond, n.Body)
   405  		}
   406  		if len(n.Else) != 0 {
   407  			fmt.Fprintf(s, " else { %v }", n.Else)
   408  		}
   409  
   410  	case OFOR:
   411  		n := n.(*ForStmt)
   412  		if !exportFormat { // TODO maybe only if FmtShort, same below
   413  			fmt.Fprintf(s, "for loop")
   414  			break
   415  		}
   416  
   417  		fmt.Fprint(s, "for")
   418  		if simpleinit {
   419  			fmt.Fprintf(s, " %v;", n.Init()[0])
   420  		} else if n.Post != nil {
   421  			fmt.Fprint(s, " ;")
   422  		}
   423  
   424  		if n.Cond != nil {
   425  			fmt.Fprintf(s, " %v", n.Cond)
   426  		}
   427  
   428  		if n.Post != nil {
   429  			fmt.Fprintf(s, "; %v", n.Post)
   430  		} else if simpleinit {
   431  			fmt.Fprint(s, ";")
   432  		}
   433  
   434  		fmt.Fprintf(s, " { %v }", n.Body)
   435  
   436  	case ORANGE:
   437  		n := n.(*RangeStmt)
   438  		if !exportFormat {
   439  			fmt.Fprint(s, "for loop")
   440  			break
   441  		}
   442  
   443  		fmt.Fprint(s, "for")
   444  		if n.Key != nil {
   445  			fmt.Fprintf(s, " %v", n.Key)
   446  			if n.Value != nil {
   447  				fmt.Fprintf(s, ", %v", n.Value)
   448  			}
   449  			fmt.Fprint(s, " =")
   450  		}
   451  		fmt.Fprintf(s, " range %v { %v }", n.X, n.Body)
   452  
   453  	case OSELECT:
   454  		n := n.(*SelectStmt)
   455  		if !exportFormat {
   456  			fmt.Fprintf(s, "%v statement", n.Op())
   457  			break
   458  		}
   459  		fmt.Fprintf(s, "select { %v }", n.Cases)
   460  
   461  	case OSWITCH:
   462  		n := n.(*SwitchStmt)
   463  		if !exportFormat {
   464  			fmt.Fprintf(s, "%v statement", n.Op())
   465  			break
   466  		}
   467  		fmt.Fprintf(s, "switch")
   468  		if simpleinit {
   469  			fmt.Fprintf(s, " %v;", n.Init()[0])
   470  		}
   471  		if n.Tag != nil {
   472  			fmt.Fprintf(s, " %v ", n.Tag)
   473  		}
   474  		fmt.Fprintf(s, " { %v }", n.Cases)
   475  
   476  	case OCASE:
   477  		n := n.(*CaseClause)
   478  		if len(n.List) != 0 {
   479  			fmt.Fprintf(s, "case %.v", n.List)
   480  		} else {
   481  			fmt.Fprint(s, "default")
   482  		}
   483  		fmt.Fprintf(s, ": %v", n.Body)
   484  
   485  	case OBREAK, OCONTINUE, OGOTO, OFALL:
   486  		n := n.(*BranchStmt)
   487  		if n.Label != nil {
   488  			fmt.Fprintf(s, "%v %v", n.Op(), n.Label)
   489  		} else {
   490  			fmt.Fprintf(s, "%v", n.Op())
   491  		}
   492  
   493  	case OLABEL:
   494  		n := n.(*LabelStmt)
   495  		fmt.Fprintf(s, "%v: ", n.Label)
   496  	}
   497  
   498  	if extrablock {
   499  		fmt.Fprint(s, "}")
   500  	}
   501  }
   502  
   503  func exprFmt(n Node, s fmt.State, prec int) {
   504  	// NOTE(rsc): This code used to support the text-based
   505  	// which was more aggressive about printing full Go syntax
   506  	// (for example, an actual loop instead of "for loop").
   507  	// The code is preserved for now in case we want to expand
   508  	// any of those shortenings later. Or maybe we will delete
   509  	// the code. But for now, keep it.
   510  	const exportFormat = false
   511  
   512  	for {
   513  		if n == nil {
   514  			fmt.Fprint(s, "<nil>")
   515  			return
   516  		}
   517  
   518  		// We always want the original, if any.
   519  		if o := Orig(n); o != n {
   520  			n = o
   521  			continue
   522  		}
   523  
   524  		// Skip implicit operations introduced during typechecking.
   525  		switch nn := n; nn.Op() {
   526  		case OADDR:
   527  			nn := nn.(*AddrExpr)
   528  			if nn.Implicit() {
   529  				n = nn.X
   530  				continue
   531  			}
   532  		case ODEREF:
   533  			nn := nn.(*StarExpr)
   534  			if nn.Implicit() {
   535  				n = nn.X
   536  				continue
   537  			}
   538  		case OCONV, OCONVNOP, OCONVIFACE, OCONVIDATA:
   539  			nn := nn.(*ConvExpr)
   540  			if nn.Implicit() {
   541  				n = nn.X
   542  				continue
   543  			}
   544  		}
   545  
   546  		break
   547  	}
   548  
   549  	nprec := OpPrec[n.Op()]
   550  	if n.Op() == OTYPE && n.Type() != nil && n.Type().IsPtr() {
   551  		nprec = OpPrec[ODEREF]
   552  	}
   553  
   554  	if prec > nprec {
   555  		fmt.Fprintf(s, "(%v)", n)
   556  		return
   557  	}
   558  
   559  	if n, ok := n.(*RawOrigExpr); ok {
   560  		fmt.Fprint(s, n.Raw)
   561  		return
   562  	}
   563  
   564  	switch n.Op() {
   565  	case OPAREN:
   566  		n := n.(*ParenExpr)
   567  		fmt.Fprintf(s, "(%v)", n.X)
   568  
   569  	case ONIL:
   570  		fmt.Fprint(s, "nil")
   571  
   572  	case OLITERAL: // this is a bit of a mess
   573  		if !exportFormat && n.Sym() != nil {
   574  			fmt.Fprint(s, n.Sym())
   575  			return
   576  		}
   577  
   578  		needUnparen := false
   579  		if n.Type() != nil && !n.Type().IsUntyped() {
   580  			// Need parens when type begins with what might
   581  			// be misinterpreted as a unary operator: * or <-.
   582  			if n.Type().IsPtr() || (n.Type().IsChan() && n.Type().ChanDir() == types.Crecv) {
   583  				fmt.Fprintf(s, "(%v)(", n.Type())
   584  			} else {
   585  				fmt.Fprintf(s, "%v(", n.Type())
   586  			}
   587  			needUnparen = true
   588  		}
   589  
   590  		if n.Type() == types.UntypedRune {
   591  			switch x, ok := constant.Uint64Val(n.Val()); {
   592  			case !ok:
   593  				fallthrough
   594  			default:
   595  				fmt.Fprintf(s, "('\\x00' + %v)", n.Val())
   596  
   597  			case x < utf8.RuneSelf:
   598  				fmt.Fprintf(s, "%q", x)
   599  
   600  			case x < 1<<16:
   601  				fmt.Fprintf(s, "'\\u%04x'", x)
   602  
   603  			case x <= utf8.MaxRune:
   604  				fmt.Fprintf(s, "'\\U%08x'", x)
   605  			}
   606  		} else {
   607  			fmt.Fprint(s, types.FmtConst(n.Val(), s.Flag('#')))
   608  		}
   609  
   610  		if needUnparen {
   611  			fmt.Fprintf(s, ")")
   612  		}
   613  
   614  	case ODCLFUNC:
   615  		n := n.(*Func)
   616  		if sym := n.Sym(); sym != nil {
   617  			fmt.Fprint(s, sym)
   618  			return
   619  		}
   620  		fmt.Fprintf(s, "<unnamed Func>")
   621  
   622  	case ONAME:
   623  		n := n.(*Name)
   624  		// Special case: name used as local variable in export.
   625  		// _ becomes ~b%d internally; print as _ for export
   626  		if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' {
   627  			fmt.Fprint(s, "_")
   628  			return
   629  		}
   630  		fallthrough
   631  	case ONONAME:
   632  		fmt.Fprint(s, n.Sym())
   633  
   634  	case OLINKSYMOFFSET:
   635  		n := n.(*LinksymOffsetExpr)
   636  		fmt.Fprintf(s, "(%v)(%s@%d)", n.Type(), n.Linksym.Name, n.Offset_)
   637  
   638  	case OTYPE:
   639  		if n.Type() == nil && n.Sym() != nil {
   640  			fmt.Fprint(s, n.Sym())
   641  			return
   642  		}
   643  		fmt.Fprintf(s, "%v", n.Type())
   644  
   645  	case OCLOSURE:
   646  		n := n.(*ClosureExpr)
   647  		if !exportFormat {
   648  			fmt.Fprint(s, "func literal")
   649  			return
   650  		}
   651  		fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func.Body)
   652  
   653  	case OCOMPLIT:
   654  		n := n.(*CompLitExpr)
   655  		if !exportFormat {
   656  			if n.Implicit() {
   657  				fmt.Fprintf(s, "... argument")
   658  				return
   659  			}
   660  			if typ := n.Type(); typ != nil {
   661  				fmt.Fprintf(s, "%v{%s}", typ, ellipsisIf(len(n.List) != 0))
   662  				return
   663  			}
   664  			fmt.Fprint(s, "composite literal")
   665  			return
   666  		}
   667  		fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List)
   668  
   669  	case OPTRLIT:
   670  		n := n.(*AddrExpr)
   671  		fmt.Fprintf(s, "&%v", n.X)
   672  
   673  	case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
   674  		n := n.(*CompLitExpr)
   675  		if !exportFormat {
   676  			fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(len(n.List) != 0))
   677  			return
   678  		}
   679  		fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List)
   680  
   681  	case OKEY:
   682  		n := n.(*KeyExpr)
   683  		if n.Key != nil && n.Value != nil {
   684  			fmt.Fprintf(s, "%v:%v", n.Key, n.Value)
   685  			return
   686  		}
   687  
   688  		if n.Key == nil && n.Value != nil {
   689  			fmt.Fprintf(s, ":%v", n.Value)
   690  			return
   691  		}
   692  		if n.Key != nil && n.Value == nil {
   693  			fmt.Fprintf(s, "%v:", n.Key)
   694  			return
   695  		}
   696  		fmt.Fprint(s, ":")
   697  
   698  	case OSTRUCTKEY:
   699  		n := n.(*StructKeyExpr)
   700  		fmt.Fprintf(s, "%v:%v", n.Field, n.Value)
   701  
   702  	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH, OMETHVALUE, OMETHEXPR:
   703  		n := n.(*SelectorExpr)
   704  		exprFmt(n.X, s, nprec)
   705  		if n.Sel == nil {
   706  			fmt.Fprint(s, ".<nil>")
   707  			return
   708  		}
   709  		fmt.Fprintf(s, ".%s", n.Sel.Name)
   710  
   711  	case ODOTTYPE, ODOTTYPE2:
   712  		n := n.(*TypeAssertExpr)
   713  		exprFmt(n.X, s, nprec)
   714  		fmt.Fprintf(s, ".(%v)", n.Type())
   715  
   716  	case OINDEX, OINDEXMAP:
   717  		n := n.(*IndexExpr)
   718  		exprFmt(n.X, s, nprec)
   719  		fmt.Fprintf(s, "[%v]", n.Index)
   720  
   721  	case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
   722  		n := n.(*SliceExpr)
   723  		exprFmt(n.X, s, nprec)
   724  		fmt.Fprint(s, "[")
   725  		if n.Low != nil {
   726  			fmt.Fprint(s, n.Low)
   727  		}
   728  		fmt.Fprint(s, ":")
   729  		if n.High != nil {
   730  			fmt.Fprint(s, n.High)
   731  		}
   732  		if n.Op().IsSlice3() {
   733  			fmt.Fprint(s, ":")
   734  			if n.Max != nil {
   735  				fmt.Fprint(s, n.Max)
   736  			}
   737  		}
   738  		fmt.Fprint(s, "]")
   739  
   740  	case OSLICEHEADER:
   741  		n := n.(*SliceHeaderExpr)
   742  		fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Ptr, n.Len, n.Cap)
   743  
   744  	case OCOMPLEX, OCOPY, OUNSAFEADD, OUNSAFESLICE:
   745  		n := n.(*BinaryExpr)
   746  		fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.X, n.Y)
   747  
   748  	case OCONV,
   749  		OCONVIFACE,
   750  		OCONVIDATA,
   751  		OCONVNOP,
   752  		OBYTES2STR,
   753  		ORUNES2STR,
   754  		OSTR2BYTES,
   755  		OSTR2RUNES,
   756  		ORUNESTR,
   757  		OSLICE2ARR,
   758  		OSLICE2ARRPTR:
   759  		n := n.(*ConvExpr)
   760  		if n.Type() == nil || n.Type().Sym() == nil {
   761  			fmt.Fprintf(s, "(%v)", n.Type())
   762  		} else {
   763  			fmt.Fprintf(s, "%v", n.Type())
   764  		}
   765  		fmt.Fprintf(s, "(%v)", n.X)
   766  
   767  	case OREAL,
   768  		OIMAG,
   769  		OCAP,
   770  		OCLOSE,
   771  		OLEN,
   772  		ONEW,
   773  		OPANIC,
   774  		OALIGNOF,
   775  		OOFFSETOF,
   776  		OSIZEOF:
   777  		n := n.(*UnaryExpr)
   778  		fmt.Fprintf(s, "%v(%v)", n.Op(), n.X)
   779  
   780  	case OAPPEND,
   781  		ODELETE,
   782  		OMAKE,
   783  		ORECOVER,
   784  		OPRINT,
   785  		OPRINTN:
   786  		n := n.(*CallExpr)
   787  		if n.IsDDD {
   788  			fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.Args)
   789  			return
   790  		}
   791  		fmt.Fprintf(s, "%v(%.v)", n.Op(), n.Args)
   792  
   793  	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
   794  		n := n.(*CallExpr)
   795  		exprFmt(n.X, s, nprec)
   796  		if n.IsDDD {
   797  			fmt.Fprintf(s, "(%.v...)", n.Args)
   798  			return
   799  		}
   800  		fmt.Fprintf(s, "(%.v)", n.Args)
   801  
   802  	case OINLCALL:
   803  		n := n.(*InlinedCallExpr)
   804  		// TODO(mdempsky): Print Init and/or Body?
   805  		if len(n.ReturnVars) == 1 {
   806  			fmt.Fprintf(s, "%v", n.ReturnVars[0])
   807  			return
   808  		}
   809  		fmt.Fprintf(s, "(.%v)", n.ReturnVars)
   810  
   811  	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
   812  		n := n.(*MakeExpr)
   813  		if n.Cap != nil {
   814  			fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Len, n.Cap)
   815  			return
   816  		}
   817  		if n.Len != nil && (n.Op() == OMAKESLICE || !n.Len.Type().IsUntyped()) {
   818  			fmt.Fprintf(s, "make(%v, %v)", n.Type(), n.Len)
   819  			return
   820  		}
   821  		fmt.Fprintf(s, "make(%v)", n.Type())
   822  
   823  	case OMAKESLICECOPY:
   824  		n := n.(*MakeExpr)
   825  		fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Len, n.Cap)
   826  
   827  	case OPLUS, ONEG, OBITNOT, ONOT, ORECV:
   828  		// Unary
   829  		n := n.(*UnaryExpr)
   830  		fmt.Fprintf(s, "%v", n.Op())
   831  		if n.X != nil && n.X.Op() == n.Op() {
   832  			fmt.Fprint(s, " ")
   833  		}
   834  		exprFmt(n.X, s, nprec+1)
   835  
   836  	case OADDR:
   837  		n := n.(*AddrExpr)
   838  		fmt.Fprintf(s, "%v", n.Op())
   839  		if n.X != nil && n.X.Op() == n.Op() {
   840  			fmt.Fprint(s, " ")
   841  		}
   842  		exprFmt(n.X, s, nprec+1)
   843  
   844  	case ODEREF:
   845  		n := n.(*StarExpr)
   846  		fmt.Fprintf(s, "%v", n.Op())
   847  		exprFmt(n.X, s, nprec+1)
   848  
   849  		// Binary
   850  	case OADD,
   851  		OAND,
   852  		OANDNOT,
   853  		ODIV,
   854  		OEQ,
   855  		OGE,
   856  		OGT,
   857  		OLE,
   858  		OLT,
   859  		OLSH,
   860  		OMOD,
   861  		OMUL,
   862  		ONE,
   863  		OOR,
   864  		ORSH,
   865  		OSUB,
   866  		OXOR:
   867  		n := n.(*BinaryExpr)
   868  		exprFmt(n.X, s, nprec)
   869  		fmt.Fprintf(s, " %v ", n.Op())
   870  		exprFmt(n.Y, s, nprec+1)
   871  
   872  	case OANDAND,
   873  		OOROR:
   874  		n := n.(*LogicalExpr)
   875  		exprFmt(n.X, s, nprec)
   876  		fmt.Fprintf(s, " %v ", n.Op())
   877  		exprFmt(n.Y, s, nprec+1)
   878  
   879  	case OSEND:
   880  		n := n.(*SendStmt)
   881  		exprFmt(n.Chan, s, nprec)
   882  		fmt.Fprintf(s, " <- ")
   883  		exprFmt(n.Value, s, nprec+1)
   884  
   885  	case OADDSTR:
   886  		n := n.(*AddStringExpr)
   887  		for i, n1 := range n.List {
   888  			if i != 0 {
   889  				fmt.Fprint(s, " + ")
   890  			}
   891  			exprFmt(n1, s, nprec)
   892  		}
   893  	default:
   894  		fmt.Fprintf(s, "<node %v>", n.Op())
   895  	}
   896  }
   897  
   898  func ellipsisIf(b bool) string {
   899  	if b {
   900  		return "..."
   901  	}
   902  	return ""
   903  }
   904  
   905  // Nodes
   906  
   907  // Format implements formatting for a Nodes.
   908  // The valid formats are:
   909  //
   910  //	%v	Go syntax, semicolon-separated
   911  //	%.v	Go syntax, comma-separated
   912  //	%+v	Debug syntax, as in DumpList.
   913  func (l Nodes) Format(s fmt.State, verb rune) {
   914  	if s.Flag('+') && verb == 'v' {
   915  		// %+v is DumpList output
   916  		dumpNodes(s, l, 1)
   917  		return
   918  	}
   919  
   920  	if verb != 'v' {
   921  		fmt.Fprintf(s, "%%!%c(Nodes)", verb)
   922  		return
   923  	}
   924  
   925  	sep := "; "
   926  	if _, ok := s.Precision(); ok { // %.v is expr list
   927  		sep = ", "
   928  	}
   929  
   930  	for i, n := range l {
   931  		fmt.Fprint(s, n)
   932  		if i+1 < len(l) {
   933  			fmt.Fprint(s, sep)
   934  		}
   935  	}
   936  }
   937  
   938  // Dump
   939  
   940  // Dump prints the message s followed by a debug dump of n.
   941  func Dump(s string, n Node) {
   942  	fmt.Printf("%s%+v\n", s, n)
   943  }
   944  
   945  // DumpList prints the message s followed by a debug dump of each node in the list.
   946  func DumpList(s string, list Nodes) {
   947  	var buf bytes.Buffer
   948  	FDumpList(&buf, s, list)
   949  	os.Stdout.Write(buf.Bytes())
   950  }
   951  
   952  // FDumpList prints to w the message s followed by a debug dump of each node in the list.
   953  func FDumpList(w io.Writer, s string, list Nodes) {
   954  	io.WriteString(w, s)
   955  	dumpNodes(w, list, 1)
   956  	io.WriteString(w, "\n")
   957  }
   958  
   959  // indent prints indentation to w.
   960  func indent(w io.Writer, depth int) {
   961  	fmt.Fprint(w, "\n")
   962  	for i := 0; i < depth; i++ {
   963  		fmt.Fprint(w, ".   ")
   964  	}
   965  }
   966  
   967  // EscFmt is set by the escape analysis code to add escape analysis details to the node print.
   968  var EscFmt func(n Node) string
   969  
   970  // dumpNodeHeader prints the debug-format node header line to w.
   971  func dumpNodeHeader(w io.Writer, n Node) {
   972  	// Useful to see which nodes in an AST printout are actually identical
   973  	if base.Debug.DumpPtrs != 0 {
   974  		fmt.Fprintf(w, " p(%p)", n)
   975  	}
   976  
   977  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {
   978  		// Useful to see where Defn is set and what node it points to
   979  		fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
   980  	}
   981  
   982  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Curfn != nil {
   983  		// Useful to see where Defn is set and what node it points to
   984  		fmt.Fprintf(w, " curfn(%p)", n.Name().Curfn)
   985  	}
   986  	if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Outer != nil {
   987  		// Useful to see where Defn is set and what node it points to
   988  		fmt.Fprintf(w, " outer(%p)", n.Name().Outer)
   989  	}
   990  
   991  	if EscFmt != nil {
   992  		if esc := EscFmt(n); esc != "" {
   993  			fmt.Fprintf(w, " %s", esc)
   994  		}
   995  	}
   996  
   997  	if n.Sym() != nil && n.Op() != ONAME && n.Op() != ONONAME && n.Op() != OTYPE {
   998  		fmt.Fprintf(w, " %+v", n.Sym())
   999  	}
  1000  
  1001  	// Print Node-specific fields of basic type in header line.
  1002  	v := reflect.ValueOf(n).Elem()
  1003  	t := v.Type()
  1004  	nf := t.NumField()
  1005  	for i := 0; i < nf; i++ {
  1006  		tf := t.Field(i)
  1007  		if tf.PkgPath != "" {
  1008  			// skip unexported field - Interface will fail
  1009  			continue
  1010  		}
  1011  		k := tf.Type.Kind()
  1012  		if reflect.Bool <= k && k <= reflect.Complex128 {
  1013  			name := strings.TrimSuffix(tf.Name, "_")
  1014  			vf := v.Field(i)
  1015  			vfi := vf.Interface()
  1016  			if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && isZero(vf) {
  1017  				continue
  1018  			}
  1019  			if vfi == true {
  1020  				fmt.Fprintf(w, " %s", name)
  1021  			} else {
  1022  				fmt.Fprintf(w, " %s:%+v", name, vf.Interface())
  1023  			}
  1024  		}
  1025  	}
  1026  
  1027  	// Print Node-specific booleans by looking for methods.
  1028  	// Different v, t from above - want *Struct not Struct, for methods.
  1029  	v = reflect.ValueOf(n)
  1030  	t = v.Type()
  1031  	nm := t.NumMethod()
  1032  	for i := 0; i < nm; i++ {
  1033  		tm := t.Method(i)
  1034  		if tm.PkgPath != "" {
  1035  			// skip unexported method - call will fail
  1036  			continue
  1037  		}
  1038  		m := v.Method(i)
  1039  		mt := m.Type()
  1040  		if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {
  1041  			// TODO(rsc): Remove the func/defer/recover wrapping,
  1042  			// which is guarding against panics in miniExpr,
  1043  			// once we get down to the simpler state in which
  1044  			// nodes have no getter methods that aren't allowed to be called.
  1045  			func() {
  1046  				defer func() { recover() }()
  1047  				if m.Call(nil)[0].Bool() {
  1048  					name := strings.TrimSuffix(tm.Name, "_")
  1049  					fmt.Fprintf(w, " %s", name)
  1050  				}
  1051  			}()
  1052  		}
  1053  	}
  1054  
  1055  	if n.Op() == OCLOSURE {
  1056  		n := n.(*ClosureExpr)
  1057  		if fn := n.Func; fn != nil && fn.Nname.Sym() != nil {
  1058  			fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
  1059  		}
  1060  	}
  1061  
  1062  	if n.Type() != nil {
  1063  		if n.Op() == OTYPE {
  1064  			fmt.Fprintf(w, " type")
  1065  		}
  1066  		fmt.Fprintf(w, " %+v", n.Type())
  1067  	}
  1068  	if n.Typecheck() != 0 {
  1069  		fmt.Fprintf(w, " tc(%d)", n.Typecheck())
  1070  	}
  1071  
  1072  	if n.Pos().IsKnown() {
  1073  		fmt.Fprint(w, " # ")
  1074  		switch n.Pos().IsStmt() {
  1075  		case src.PosNotStmt:
  1076  			fmt.Fprint(w, "_") // "-" would be confusing
  1077  		case src.PosIsStmt:
  1078  			fmt.Fprint(w, "+")
  1079  		}
  1080  		for i, pos := range base.Ctxt.AllPos(n.Pos(), nil) {
  1081  			if i > 0 {
  1082  				fmt.Fprint(w, ",")
  1083  			}
  1084  			// TODO(mdempsky): Print line pragma details too.
  1085  			file := filepath.Base(pos.Filename())
  1086  			// Note: this output will be parsed by ssa/html.go:(*HTMLWriter).WriteAST. Keep in sync.
  1087  			fmt.Fprintf(w, "%s:%d:%d", file, pos.Line(), pos.Col())
  1088  		}
  1089  	}
  1090  }
  1091  
  1092  func dumpNode(w io.Writer, n Node, depth int) {
  1093  	indent(w, depth)
  1094  	if depth > 40 {
  1095  		fmt.Fprint(w, "...")
  1096  		return
  1097  	}
  1098  
  1099  	if n == nil {
  1100  		fmt.Fprint(w, "NilIrNode")
  1101  		return
  1102  	}
  1103  
  1104  	if len(n.Init()) != 0 {
  1105  		fmt.Fprintf(w, "%+v-init", n.Op())
  1106  		dumpNodes(w, n.Init(), depth+1)
  1107  		indent(w, depth)
  1108  	}
  1109  
  1110  	switch n.Op() {
  1111  	default:
  1112  		fmt.Fprintf(w, "%+v", n.Op())
  1113  		dumpNodeHeader(w, n)
  1114  
  1115  	case OLITERAL:
  1116  		fmt.Fprintf(w, "%+v-%v", n.Op(), n.Val())
  1117  		dumpNodeHeader(w, n)
  1118  		return
  1119  
  1120  	case ONAME, ONONAME:
  1121  		if n.Sym() != nil {
  1122  			fmt.Fprintf(w, "%+v-%+v", n.Op(), n.Sym())
  1123  		} else {
  1124  			fmt.Fprintf(w, "%+v", n.Op())
  1125  		}
  1126  		dumpNodeHeader(w, n)
  1127  		return
  1128  
  1129  	case OLINKSYMOFFSET:
  1130  		n := n.(*LinksymOffsetExpr)
  1131  		fmt.Fprintf(w, "%+v-%v", n.Op(), n.Linksym)
  1132  		// Offset is almost always 0, so only print when it's interesting.
  1133  		if n.Offset_ != 0 {
  1134  			fmt.Fprintf(w, "%+v", n.Offset_)
  1135  		}
  1136  		dumpNodeHeader(w, n)
  1137  
  1138  	case OASOP:
  1139  		n := n.(*AssignOpStmt)
  1140  		fmt.Fprintf(w, "%+v-%+v", n.Op(), n.AsOp)
  1141  		dumpNodeHeader(w, n)
  1142  
  1143  	case OTYPE:
  1144  		fmt.Fprintf(w, "%+v %+v", n.Op(), n.Sym())
  1145  		dumpNodeHeader(w, n)
  1146  		return
  1147  
  1148  	case OCLOSURE:
  1149  		fmt.Fprintf(w, "%+v", n.Op())
  1150  		dumpNodeHeader(w, n)
  1151  
  1152  	case ODCLFUNC:
  1153  		// Func has many fields we don't want to print.
  1154  		// Bypass reflection and just print what we want.
  1155  		n := n.(*Func)
  1156  		fmt.Fprintf(w, "%+v", n.Op())
  1157  		dumpNodeHeader(w, n)
  1158  		fn := n
  1159  		if len(fn.Dcl) > 0 {
  1160  			indent(w, depth)
  1161  			fmt.Fprintf(w, "%+v-Dcl", n.Op())
  1162  			for _, dcl := range n.Dcl {
  1163  				dumpNode(w, dcl, depth+1)
  1164  			}
  1165  		}
  1166  		if len(fn.ClosureVars) > 0 {
  1167  			indent(w, depth)
  1168  			fmt.Fprintf(w, "%+v-ClosureVars", n.Op())
  1169  			for _, cv := range fn.ClosureVars {
  1170  				dumpNode(w, cv, depth+1)
  1171  			}
  1172  		}
  1173  		if len(fn.Enter) > 0 {
  1174  			indent(w, depth)
  1175  			fmt.Fprintf(w, "%+v-Enter", n.Op())
  1176  			dumpNodes(w, fn.Enter, depth+1)
  1177  		}
  1178  		if len(fn.Body) > 0 {
  1179  			indent(w, depth)
  1180  			fmt.Fprintf(w, "%+v-body", n.Op())
  1181  			dumpNodes(w, fn.Body, depth+1)
  1182  		}
  1183  		return
  1184  	}
  1185  
  1186  	v := reflect.ValueOf(n).Elem()
  1187  	t := reflect.TypeOf(n).Elem()
  1188  	nf := t.NumField()
  1189  	for i := 0; i < nf; i++ {
  1190  		tf := t.Field(i)
  1191  		vf := v.Field(i)
  1192  		if tf.PkgPath != "" {
  1193  			// skip unexported field - Interface will fail
  1194  			continue
  1195  		}
  1196  		switch tf.Type.Kind() {
  1197  		case reflect.Interface, reflect.Ptr, reflect.Slice:
  1198  			if vf.IsNil() {
  1199  				continue
  1200  			}
  1201  		}
  1202  		name := strings.TrimSuffix(tf.Name, "_")
  1203  		// Do not bother with field name header lines for the
  1204  		// most common positional arguments: unary, binary expr,
  1205  		// index expr, send stmt, go and defer call expression.
  1206  		switch name {
  1207  		case "X", "Y", "Index", "Chan", "Value", "Call":
  1208  			name = ""
  1209  		}
  1210  		switch val := vf.Interface().(type) {
  1211  		case Node:
  1212  			if name != "" {
  1213  				indent(w, depth)
  1214  				fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1215  			}
  1216  			dumpNode(w, val, depth+1)
  1217  		case Nodes:
  1218  			if len(val) == 0 {
  1219  				continue
  1220  			}
  1221  			if name != "" {
  1222  				indent(w, depth)
  1223  				fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1224  			}
  1225  			dumpNodes(w, val, depth+1)
  1226  		default:
  1227  			if vf.Kind() == reflect.Slice && vf.Type().Elem().Implements(nodeType) {
  1228  				if vf.Len() == 0 {
  1229  					continue
  1230  				}
  1231  				if name != "" {
  1232  					indent(w, depth)
  1233  					fmt.Fprintf(w, "%+v-%s", n.Op(), name)
  1234  				}
  1235  				for i, n := 0, vf.Len(); i < n; i++ {
  1236  					dumpNode(w, vf.Index(i).Interface().(Node), depth+1)
  1237  				}
  1238  			}
  1239  		}
  1240  	}
  1241  }
  1242  
  1243  var nodeType = reflect.TypeOf((*Node)(nil)).Elem()
  1244  
  1245  func dumpNodes(w io.Writer, list Nodes, depth int) {
  1246  	if len(list) == 0 {
  1247  		fmt.Fprintf(w, " <nil>")
  1248  		return
  1249  	}
  1250  
  1251  	for _, n := range list {
  1252  		dumpNode(w, n, depth)
  1253  	}
  1254  }
  1255  
  1256  // reflect.IsZero is not available in Go 1.4 (added in Go 1.13), so we use this copy instead.
  1257  func isZero(v reflect.Value) bool {
  1258  	switch v.Kind() {
  1259  	case reflect.Bool:
  1260  		return !v.Bool()
  1261  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  1262  		return v.Int() == 0
  1263  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  1264  		return v.Uint() == 0
  1265  	case reflect.Float32, reflect.Float64:
  1266  		return math.Float64bits(v.Float()) == 0
  1267  	case reflect.Complex64, reflect.Complex128:
  1268  		c := v.Complex()
  1269  		return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
  1270  	case reflect.Array:
  1271  		for i := 0; i < v.Len(); i++ {
  1272  			if !isZero(v.Index(i)) {
  1273  				return false
  1274  			}
  1275  		}
  1276  		return true
  1277  	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
  1278  		return v.IsNil()
  1279  	case reflect.String:
  1280  		return v.Len() == 0
  1281  	case reflect.Struct:
  1282  		for i := 0; i < v.NumField(); i++ {
  1283  			if !isZero(v.Field(i)) {
  1284  				return false
  1285  			}
  1286  		}
  1287  		return true
  1288  	default:
  1289  		return false
  1290  	}
  1291  }