Home | History | Annotate | Download | only in gc
      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 gc
      6 
      7 import (
      8 	"fmt"
      9 	"strconv"
     10 	"strings"
     11 	"unicode/utf8"
     12 )
     13 
     14 // A FmtFlag value is a set of flags (or 0).
     15 // They control how the Xconv functions format their values.
     16 // See the respective function's documentation for details.
     17 type FmtFlag int
     18 
     19 // TODO(gri) The ' ' flag is not used anymore in %-formats.
     20 //           Eliminate eventually.
     21 
     22 const ( //                                 fmt.Format flag/prec or verb
     23 	FmtLeft     FmtFlag = 1 << iota // '-'
     24 	FmtSharp                        // '#'
     25 	FmtSign                         // '+'
     26 	FmtUnsigned                     // ' '               (historic: u flag)
     27 	FmtShort                        // verb == 'S'       (historic: h flag)
     28 	FmtLong                         // verb == 'L'       (historic: l flag)
     29 	FmtComma                        // '.' (== hasPrec)  (historic: , flag)
     30 	FmtByte                         // '0'               (historic: hh flag)
     31 )
     32 
     33 // fmtFlag computes the (internal) FmtFlag
     34 // value given the fmt.State and format verb.
     35 func fmtFlag(s fmt.State, verb rune) FmtFlag {
     36 	var flag FmtFlag
     37 	if s.Flag('-') {
     38 		flag |= FmtLeft
     39 	}
     40 	if s.Flag('#') {
     41 		flag |= FmtSharp
     42 	}
     43 	if s.Flag('+') {
     44 		flag |= FmtSign
     45 	}
     46 	if s.Flag(' ') {
     47 		flag |= FmtUnsigned
     48 	}
     49 	if _, ok := s.Precision(); ok {
     50 		flag |= FmtComma
     51 	}
     52 	if s.Flag('0') {
     53 		flag |= FmtByte
     54 	}
     55 	switch verb {
     56 	case 'S':
     57 		flag |= FmtShort
     58 	case 'L':
     59 		flag |= FmtLong
     60 	}
     61 	return flag
     62 }
     63 
     64 // Format conversions:
     65 // TODO(gri) verify these; eliminate those not used anymore
     66 //
     67 //	%v Op		Node opcodes
     68 //		Flags:  #: print Go syntax (automatic unless fmtmode == FDbg)
     69 //
     70 //	%j *Node	Node details
     71 //		Flags:  0: suppresses things not relevant until walk
     72 //
     73 //	%v *Val		Constant values
     74 //
     75 //	%v *Sym		Symbols
     76 //	%S              unqualified identifier in any mode
     77 //		Flags:  +,- #: mode (see below)
     78 //			0: in export mode: unqualified identifier if exported, qualified if not
     79 //
     80 //	%v *Type	Types
     81 //	%S              omit "func" and receiver in function types
     82 //	%L              definition instead of name.
     83 //		Flags:  +,- #: mode (see below)
     84 //			' ' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
     85 //
     86 //	%v *Node	Nodes
     87 //	%S              (only in +/debug mode) suppress recursion
     88 //	%L              (only in Error mode) print "foo (type Bar)"
     89 //		Flags:  +,- #: mode (see below)
     90 //
     91 //	%v Nodes	Node lists
     92 //		Flags:  those of *Node
     93 //			.: separate items with ',' instead of ';'
     94 
     95 // *Sym, *Type, and *Node types use the flags below to set the format mode
     96 const (
     97 	FErr = iota
     98 	FDbg
     99 	FTypeId
    100 )
    101 
    102 var fmtmode int = FErr
    103 
    104 var fmtpkgpfx int // "% v" stickyness for *Type objects
    105 
    106 // The mode flags '+', '-', and '#' are sticky; they persist through
    107 // recursions of *Node, *Type, and *Sym values. The ' ' flag is
    108 // sticky only on *Type recursions and only used in %-/*Sym mode.
    109 //
    110 // Example: given a *Sym: %+v %#v %-v print an identifier properly qualified for debug/export/internal mode
    111 
    112 // Useful format combinations:
    113 // TODO(gri): verify these
    114 //
    115 // *Node, Nodes:
    116 //   %+v    multiline recursive debug dump of *Node/Nodes
    117 //   %+S    non-recursive debug dump
    118 //
    119 // *Node:
    120 //   %#v    Go format
    121 //   %L     "foo (type Bar)" for error messages
    122 //
    123 // *Type:
    124 //   %#v    Go format
    125 //   %#L    type definition instead of name
    126 //   %#S    omit"func" and receiver in function signature
    127 //
    128 //   %-v    type identifiers
    129 //   %-S    type identifiers without "func" and arg names in type signatures (methodsym)
    130 //   %- v   type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
    131 
    132 func setfmode(flags *FmtFlag) (fm int) {
    133 	fm = fmtmode
    134 	if *flags&FmtSign != 0 {
    135 		fmtmode = FDbg
    136 	} else if *flags&FmtSharp != 0 {
    137 		// ignore (textual export format no longer supported)
    138 	} else if *flags&FmtLeft != 0 {
    139 		fmtmode = FTypeId
    140 	}
    141 
    142 	*flags &^= (FmtSharp | FmtLeft | FmtSign)
    143 	return
    144 }
    145 
    146 var goopnames = []string{
    147 	OADDR:     "&",
    148 	OADD:      "+",
    149 	OADDSTR:   "+",
    150 	OALIGNOF:  "unsafe.Alignof",
    151 	OANDAND:   "&&",
    152 	OANDNOT:   "&^",
    153 	OAND:      "&",
    154 	OAPPEND:   "append",
    155 	OAS:       "=",
    156 	OAS2:      "=",
    157 	OBREAK:    "break",
    158 	OCALL:     "function call", // not actual syntax
    159 	OCAP:      "cap",
    160 	OCASE:     "case",
    161 	OCLOSE:    "close",
    162 	OCOMPLEX:  "complex",
    163 	OCOM:      "^",
    164 	OCONTINUE: "continue",
    165 	OCOPY:     "copy",
    166 	ODEC:      "--",
    167 	ODELETE:   "delete",
    168 	ODEFER:    "defer",
    169 	ODIV:      "/",
    170 	OEQ:       "==",
    171 	OFALL:     "fallthrough",
    172 	OFOR:      "for",
    173 	OGE:       ">=",
    174 	OGOTO:     "goto",
    175 	OGT:       ">",
    176 	OIF:       "if",
    177 	OIMAG:     "imag",
    178 	OINC:      "++",
    179 	OIND:      "*",
    180 	OLEN:      "len",
    181 	OLE:       "<=",
    182 	OLSH:      "<<",
    183 	OLT:       "<",
    184 	OMAKE:     "make",
    185 	OMINUS:    "-",
    186 	OMOD:      "%",
    187 	OMUL:      "*",
    188 	ONEW:      "new",
    189 	ONE:       "!=",
    190 	ONOT:      "!",
    191 	OOFFSETOF: "unsafe.Offsetof",
    192 	OOROR:     "||",
    193 	OOR:       "|",
    194 	OPANIC:    "panic",
    195 	OPLUS:     "+",
    196 	OPRINTN:   "println",
    197 	OPRINT:    "print",
    198 	ORANGE:    "range",
    199 	OREAL:     "real",
    200 	ORECV:     "<-",
    201 	ORECOVER:  "recover",
    202 	ORETURN:   "return",
    203 	ORSH:      ">>",
    204 	OSELECT:   "select",
    205 	OSEND:     "<-",
    206 	OSIZEOF:   "unsafe.Sizeof",
    207 	OSUB:      "-",
    208 	OSWITCH:   "switch",
    209 	OXOR:      "^",
    210 	OXFALL:    "fallthrough",
    211 }
    212 
    213 func (o Op) String() string {
    214 	return fmt.Sprint(o)
    215 }
    216 
    217 func (o Op) GoString() string {
    218 	return fmt.Sprintf("%#v", o)
    219 }
    220 
    221 func (o Op) Format(s fmt.State, verb rune) {
    222 	switch verb {
    223 	case 'v':
    224 		o.oconv(s, fmtFlag(s, verb))
    225 
    226 	default:
    227 		fmt.Fprintf(s, "%%!%c(Op=%d)", verb, int(o))
    228 	}
    229 }
    230 
    231 func (o Op) oconv(s fmt.State, flag FmtFlag) {
    232 	if (flag&FmtSharp != 0) || fmtmode != FDbg {
    233 		if o >= 0 && int(o) < len(goopnames) && goopnames[o] != "" {
    234 			fmt.Fprint(s, goopnames[o])
    235 			return
    236 		}
    237 	}
    238 
    239 	if o >= 0 && int(o) < len(opnames) && opnames[o] != "" {
    240 		fmt.Fprint(s, opnames[o])
    241 		return
    242 	}
    243 
    244 	fmt.Fprintf(s, "O-%d", int(o))
    245 }
    246 
    247 var classnames = []string{
    248 	"Pxxx",
    249 	"PEXTERN",
    250 	"PAUTO",
    251 	"PAUTOHEAP",
    252 	"PPARAM",
    253 	"PPARAMOUT",
    254 	"PFUNC",
    255 }
    256 
    257 func (n *Node) Format(s fmt.State, verb rune) {
    258 	switch verb {
    259 	case 'v', 'S', 'L':
    260 		n.Nconv(s, fmtFlag(s, verb))
    261 
    262 	case 'j':
    263 		n.jconv(s, fmtFlag(s, verb))
    264 
    265 	default:
    266 		fmt.Fprintf(s, "%%!%c(*Node=%p)", verb, n)
    267 	}
    268 }
    269 
    270 // *Node details
    271 func (n *Node) jconv(s fmt.State, flag FmtFlag) {
    272 	c := flag & FmtShort
    273 
    274 	if c == 0 && n.Ullman != 0 {
    275 		fmt.Fprintf(s, " u(%d)", n.Ullman)
    276 	}
    277 
    278 	if c == 0 && n.Addable {
    279 		fmt.Fprintf(s, " a(%v)", n.Addable)
    280 	}
    281 
    282 	if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
    283 		fmt.Fprintf(s, " g(%d)", n.Name.Vargen)
    284 	}
    285 
    286 	if n.Lineno != 0 {
    287 		fmt.Fprintf(s, " l(%d)", n.Lineno)
    288 	}
    289 
    290 	if c == 0 && n.Xoffset != BADWIDTH {
    291 		fmt.Fprintf(s, " x(%d)", n.Xoffset)
    292 	}
    293 
    294 	if n.Class != 0 {
    295 		if int(n.Class) < len(classnames) {
    296 			fmt.Fprintf(s, " class(%s)", classnames[n.Class])
    297 		} else {
    298 			fmt.Fprintf(s, " class(%d?)", n.Class)
    299 		}
    300 	}
    301 
    302 	if n.Colas {
    303 		fmt.Fprintf(s, " colas(%v)", n.Colas)
    304 	}
    305 
    306 	if n.Name != nil && n.Name.Funcdepth != 0 {
    307 		fmt.Fprintf(s, " f(%d)", n.Name.Funcdepth)
    308 	}
    309 	if n.Func != nil && n.Func.Depth != 0 {
    310 		fmt.Fprintf(s, " ff(%d)", n.Func.Depth)
    311 	}
    312 
    313 	switch n.Esc {
    314 	case EscUnknown:
    315 		break
    316 
    317 	case EscHeap:
    318 		fmt.Fprint(s, " esc(h)")
    319 
    320 	case EscNone:
    321 		fmt.Fprint(s, " esc(no)")
    322 
    323 	case EscNever:
    324 		if c == 0 {
    325 			fmt.Fprint(s, " esc(N)")
    326 		}
    327 
    328 	default:
    329 		fmt.Fprintf(s, " esc(%d)", n.Esc)
    330 	}
    331 
    332 	if e, ok := n.Opt().(*NodeEscState); ok && e.Loopdepth != 0 {
    333 		fmt.Fprintf(s, " ld(%d)", e.Loopdepth)
    334 	}
    335 
    336 	if c == 0 && n.Typecheck != 0 {
    337 		fmt.Fprintf(s, " tc(%d)", n.Typecheck)
    338 	}
    339 
    340 	if c == 0 && n.IsStatic {
    341 		fmt.Fprint(s, " static")
    342 	}
    343 
    344 	if n.Isddd {
    345 		fmt.Fprintf(s, " isddd(%v)", n.Isddd)
    346 	}
    347 
    348 	if n.Implicit {
    349 		fmt.Fprintf(s, " implicit(%v)", n.Implicit)
    350 	}
    351 
    352 	if n.Embedded != 0 {
    353 		fmt.Fprintf(s, " embedded(%d)", n.Embedded)
    354 	}
    355 
    356 	if n.Addrtaken {
    357 		fmt.Fprint(s, " addrtaken")
    358 	}
    359 
    360 	if n.Assigned {
    361 		fmt.Fprint(s, " assigned")
    362 	}
    363 	if n.Bounded {
    364 		fmt.Fprint(s, " bounded")
    365 	}
    366 	if n.NonNil {
    367 		fmt.Fprint(s, " nonnil")
    368 	}
    369 
    370 	if c == 0 && n.Used {
    371 		fmt.Fprintf(s, " used(%v)", n.Used)
    372 	}
    373 }
    374 
    375 func (v Val) Format(s fmt.State, verb rune) {
    376 	switch verb {
    377 	case 'v':
    378 		v.vconv(s, fmtFlag(s, verb))
    379 
    380 	default:
    381 		fmt.Fprintf(s, "%%!%c(Val=%T)", verb, v)
    382 	}
    383 }
    384 
    385 func (v Val) vconv(s fmt.State, flag FmtFlag) {
    386 	switch u := v.U.(type) {
    387 	case *Mpint:
    388 		if !u.Rune {
    389 			if flag&FmtSharp != 0 {
    390 				fmt.Fprint(s, bconv(u, FmtSharp))
    391 				return
    392 			}
    393 			fmt.Fprint(s, bconv(u, 0))
    394 			return
    395 		}
    396 
    397 		switch x := u.Int64(); {
    398 		case ' ' <= x && x < utf8.RuneSelf && x != '\\' && x != '\'':
    399 			fmt.Fprintf(s, "'%c'", int(x))
    400 
    401 		case 0 <= x && x < 1<<16:
    402 			fmt.Fprintf(s, "'\\u%04x'", uint(int(x)))
    403 
    404 		case 0 <= x && x <= utf8.MaxRune:
    405 			fmt.Fprintf(s, "'\\U%08x'", uint64(x))
    406 
    407 		default:
    408 			fmt.Fprintf(s, "('\\x00' + %v)", u)
    409 		}
    410 
    411 	case *Mpflt:
    412 		if flag&FmtSharp != 0 {
    413 			fmt.Fprint(s, fconv(u, 0))
    414 			return
    415 		}
    416 		fmt.Fprint(s, fconv(u, FmtSharp))
    417 		return
    418 
    419 	case *Mpcplx:
    420 		switch {
    421 		case flag&FmtSharp != 0:
    422 			fmt.Fprintf(s, "(%v+%vi)", &u.Real, &u.Imag)
    423 
    424 		case v.U.(*Mpcplx).Real.CmpFloat64(0) == 0:
    425 			fmt.Fprintf(s, "%vi", fconv(&u.Imag, FmtSharp))
    426 
    427 		case v.U.(*Mpcplx).Imag.CmpFloat64(0) == 0:
    428 			fmt.Fprint(s, fconv(&u.Real, FmtSharp))
    429 
    430 		case v.U.(*Mpcplx).Imag.CmpFloat64(0) < 0:
    431 			fmt.Fprintf(s, "(%v%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
    432 
    433 		default:
    434 			fmt.Fprintf(s, "(%v+%vi)", fconv(&u.Real, FmtSharp), fconv(&u.Imag, FmtSharp))
    435 		}
    436 
    437 	case string:
    438 		fmt.Fprint(s, strconv.Quote(u))
    439 
    440 	case bool:
    441 		t := "false"
    442 		if u {
    443 			t = "true"
    444 		}
    445 		fmt.Fprint(s, t)
    446 
    447 	case *NilVal:
    448 		fmt.Fprint(s, "nil")
    449 
    450 	default:
    451 		fmt.Fprintf(s, "<ctype=%d>", v.Ctype())
    452 	}
    453 }
    454 
    455 /*
    456 s%,%,\n%g
    457 s%\n+%\n%g
    458 s%^[	]*T%%g
    459 s%,.*%%g
    460 s%.+%	[T&]		= "&",%g
    461 s%^	........*\]%&~%g
    462 s%~	%%g
    463 */
    464 var etnames = []string{
    465 	Txxx:        "Txxx",
    466 	TINT:        "INT",
    467 	TUINT:       "UINT",
    468 	TINT8:       "INT8",
    469 	TUINT8:      "UINT8",
    470 	TINT16:      "INT16",
    471 	TUINT16:     "UINT16",
    472 	TINT32:      "INT32",
    473 	TUINT32:     "UINT32",
    474 	TINT64:      "INT64",
    475 	TUINT64:     "UINT64",
    476 	TUINTPTR:    "UINTPTR",
    477 	TFLOAT32:    "FLOAT32",
    478 	TFLOAT64:    "FLOAT64",
    479 	TCOMPLEX64:  "COMPLEX64",
    480 	TCOMPLEX128: "COMPLEX128",
    481 	TBOOL:       "BOOL",
    482 	TPTR32:      "PTR32",
    483 	TPTR64:      "PTR64",
    484 	TFUNC:       "FUNC",
    485 	TARRAY:      "ARRAY",
    486 	TSLICE:      "SLICE",
    487 	TSTRUCT:     "STRUCT",
    488 	TCHAN:       "CHAN",
    489 	TMAP:        "MAP",
    490 	TINTER:      "INTER",
    491 	TFORW:       "FORW",
    492 	TSTRING:     "STRING",
    493 	TUNSAFEPTR:  "TUNSAFEPTR",
    494 	TANY:        "ANY",
    495 	TIDEAL:      "TIDEAL",
    496 	TNIL:        "TNIL",
    497 	TBLANK:      "TBLANK",
    498 	TFUNCARGS:   "TFUNCARGS",
    499 	TCHANARGS:   "TCHANARGS",
    500 	TINTERMETH:  "TINTERMETH",
    501 	TDDDFIELD:   "TDDDFIELD",
    502 }
    503 
    504 func (et EType) String() string {
    505 	if int(et) < len(etnames) && etnames[et] != "" {
    506 		return etnames[et]
    507 	}
    508 	return fmt.Sprintf("E-%d", et)
    509 }
    510 
    511 func (s *Sym) symfmt(flag FmtFlag) string {
    512 	if s.Pkg != nil && flag&FmtShort == 0 {
    513 		switch fmtmode {
    514 		case FErr: // This is for the user
    515 			if s.Pkg == builtinpkg || s.Pkg == localpkg {
    516 				return s.Name
    517 			}
    518 
    519 			// If the name was used by multiple packages, display the full path,
    520 			if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
    521 				return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
    522 			}
    523 			return s.Pkg.Name + "." + s.Name
    524 
    525 		case FDbg:
    526 			return s.Pkg.Name + "." + s.Name
    527 
    528 		case FTypeId:
    529 			if flag&FmtUnsigned != 0 {
    530 				return s.Pkg.Name + "." + s.Name // dcommontype, typehash
    531 			}
    532 			return s.Pkg.Prefix + "." + s.Name // (methodsym), typesym, weaksym
    533 		}
    534 	}
    535 
    536 	if flag&FmtByte != 0 {
    537 		// FmtByte (hh) implies FmtShort (h)
    538 		// skip leading "type." in method name
    539 		name := s.Name
    540 		if i := strings.LastIndex(name, "."); i >= 0 {
    541 			name = name[i+1:]
    542 		}
    543 
    544 		if fmtmode == FDbg {
    545 			return fmt.Sprintf("@%q.%s", s.Pkg.Path, name)
    546 		}
    547 
    548 		return name
    549 	}
    550 
    551 	return s.Name
    552 }
    553 
    554 var basicnames = []string{
    555 	TINT:        "int",
    556 	TUINT:       "uint",
    557 	TINT8:       "int8",
    558 	TUINT8:      "uint8",
    559 	TINT16:      "int16",
    560 	TUINT16:     "uint16",
    561 	TINT32:      "int32",
    562 	TUINT32:     "uint32",
    563 	TINT64:      "int64",
    564 	TUINT64:     "uint64",
    565 	TUINTPTR:    "uintptr",
    566 	TFLOAT32:    "float32",
    567 	TFLOAT64:    "float64",
    568 	TCOMPLEX64:  "complex64",
    569 	TCOMPLEX128: "complex128",
    570 	TBOOL:       "bool",
    571 	TANY:        "any",
    572 	TSTRING:     "string",
    573 	TNIL:        "nil",
    574 	TIDEAL:      "untyped number",
    575 	TBLANK:      "blank",
    576 }
    577 
    578 func (t *Type) typefmt(flag FmtFlag) string {
    579 	if t == nil {
    580 		return "<T>"
    581 	}
    582 
    583 	if t == bytetype || t == runetype {
    584 		// in %-T mode collapse rune and byte with their originals.
    585 		if fmtmode != FTypeId {
    586 			return t.Sym.sconv(FmtShort)
    587 		}
    588 		t = Types[t.Etype]
    589 	}
    590 
    591 	if t == errortype {
    592 		return "error"
    593 	}
    594 
    595 	// Unless the 'l' flag was specified, if the type has a name, just print that name.
    596 	if flag&FmtLong == 0 && t.Sym != nil && t != Types[t.Etype] {
    597 		switch fmtmode {
    598 		case FTypeId:
    599 			if flag&FmtShort != 0 {
    600 				if t.Vargen != 0 {
    601 					return fmt.Sprintf("%v%d", t.Sym.sconv(FmtShort), t.Vargen)
    602 				}
    603 				return t.Sym.sconv(FmtShort)
    604 			}
    605 
    606 			if flag&FmtUnsigned != 0 {
    607 				return t.Sym.sconv(FmtUnsigned)
    608 			}
    609 
    610 			if t.Sym.Pkg == localpkg && t.Vargen != 0 {
    611 				return fmt.Sprintf("%v%d", t.Sym, t.Vargen)
    612 			}
    613 		}
    614 
    615 		return t.Sym.String()
    616 	}
    617 
    618 	if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
    619 		prefix := ""
    620 		if fmtmode == FErr && (t == idealbool || t == idealstring) {
    621 			prefix = "untyped "
    622 		}
    623 		return prefix + basicnames[t.Etype]
    624 	}
    625 
    626 	if fmtmode == FDbg {
    627 		fmtmode = 0
    628 		str := t.Etype.String() + "-" + t.typefmt(flag)
    629 		fmtmode = FDbg
    630 		return str
    631 	}
    632 
    633 	switch t.Etype {
    634 	case TPTR32, TPTR64:
    635 		if fmtmode == FTypeId && (flag&FmtShort != 0) {
    636 			return "*" + t.Elem().tconv(FmtShort)
    637 		}
    638 		return "*" + t.Elem().String()
    639 
    640 	case TARRAY:
    641 		if t.isDDDArray() {
    642 			return "[...]" + t.Elem().String()
    643 		}
    644 		return fmt.Sprintf("[%d]%v", t.NumElem(), t.Elem())
    645 
    646 	case TSLICE:
    647 		return "[]" + t.Elem().String()
    648 
    649 	case TCHAN:
    650 		switch t.ChanDir() {
    651 		case Crecv:
    652 			return "<-chan " + t.Elem().String()
    653 
    654 		case Csend:
    655 			return "chan<- " + t.Elem().String()
    656 		}
    657 
    658 		if t.Elem() != nil && t.Elem().IsChan() && t.Elem().Sym == nil && t.Elem().ChanDir() == Crecv {
    659 			return "chan (" + t.Elem().String() + ")"
    660 		}
    661 		return "chan " + t.Elem().String()
    662 
    663 	case TMAP:
    664 		return "map[" + t.Key().String() + "]" + t.Val().String()
    665 
    666 	case TINTER:
    667 		if t.IsEmptyInterface() {
    668 			return "interface {}"
    669 		}
    670 		buf := make([]byte, 0, 64)
    671 		buf = append(buf, "interface {"...)
    672 		for i, f := range t.Fields().Slice() {
    673 			if i != 0 {
    674 				buf = append(buf, ';')
    675 			}
    676 			buf = append(buf, ' ')
    677 			switch {
    678 			case f.Sym == nil:
    679 				// Check first that a symbol is defined for this type.
    680 				// Wrong interface definitions may have types lacking a symbol.
    681 				break
    682 			case exportname(f.Sym.Name):
    683 				buf = append(buf, f.Sym.sconv(FmtShort)...)
    684 			default:
    685 				buf = append(buf, f.Sym.sconv(FmtUnsigned)...)
    686 			}
    687 			buf = append(buf, f.Type.tconv(FmtShort)...)
    688 		}
    689 		if t.NumFields() != 0 {
    690 			buf = append(buf, ' ')
    691 		}
    692 		buf = append(buf, '}')
    693 		return string(buf)
    694 
    695 	case TFUNC:
    696 		buf := make([]byte, 0, 64)
    697 		if flag&FmtShort != 0 {
    698 			// no leading func
    699 		} else {
    700 			if t.Recv() != nil {
    701 				buf = append(buf, "method"...)
    702 				buf = append(buf, t.Recvs().String()...)
    703 				buf = append(buf, ' ')
    704 			}
    705 			buf = append(buf, "func"...)
    706 		}
    707 		buf = append(buf, t.Params().String()...)
    708 
    709 		switch t.Results().NumFields() {
    710 		case 0:
    711 			// nothing to do
    712 
    713 		case 1:
    714 			buf = append(buf, ' ')
    715 			buf = append(buf, t.Results().Field(0).Type.String()...) // struct->field->field's type
    716 
    717 		default:
    718 			buf = append(buf, ' ')
    719 			buf = append(buf, t.Results().String()...)
    720 		}
    721 		return string(buf)
    722 
    723 	case TSTRUCT:
    724 		if m := t.StructType().Map; m != nil {
    725 			mt := m.MapType()
    726 			// Format the bucket struct for map[x]y as map.bucket[x]y.
    727 			// This avoids a recursive print that generates very long names.
    728 			if mt.Bucket == t {
    729 				return "map.bucket[" + m.Key().String() + "]" + m.Val().String()
    730 			}
    731 
    732 			if mt.Hmap == t {
    733 				return "map.hdr[" + m.Key().String() + "]" + m.Val().String()
    734 			}
    735 
    736 			if mt.Hiter == t {
    737 				return "map.iter[" + m.Key().String() + "]" + m.Val().String()
    738 			}
    739 
    740 			yyerror("unknown internal map type")
    741 		}
    742 
    743 		buf := make([]byte, 0, 64)
    744 		if t.IsFuncArgStruct() {
    745 			buf = append(buf, '(')
    746 			var flag1 FmtFlag
    747 			if fmtmode == FTypeId || fmtmode == FErr { // no argument names on function signature, and no "noescape"/"nosplit" tags
    748 				flag1 = FmtShort
    749 			}
    750 			for i, f := range t.Fields().Slice() {
    751 				if i != 0 {
    752 					buf = append(buf, ", "...)
    753 				}
    754 				buf = append(buf, fldconv(f, flag1)...)
    755 			}
    756 			buf = append(buf, ')')
    757 		} else {
    758 			buf = append(buf, "struct {"...)
    759 			for i, f := range t.Fields().Slice() {
    760 				if i != 0 {
    761 					buf = append(buf, ';')
    762 				}
    763 				buf = append(buf, ' ')
    764 				buf = append(buf, fldconv(f, FmtLong)...)
    765 			}
    766 			if t.NumFields() != 0 {
    767 				buf = append(buf, ' ')
    768 			}
    769 			buf = append(buf, '}')
    770 		}
    771 		return string(buf)
    772 
    773 	case TFORW:
    774 		if t.Sym != nil {
    775 			return "undefined " + t.Sym.String()
    776 		}
    777 		return "undefined"
    778 
    779 	case TUNSAFEPTR:
    780 		return "unsafe.Pointer"
    781 
    782 	case TDDDFIELD:
    783 		return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.DDDField())
    784 
    785 	case Txxx:
    786 		return "Txxx"
    787 	}
    788 
    789 	// Don't know how to handle - fall back to detailed prints.
    790 	return fmt.Sprintf("%v <%v> %v", t.Etype, t.Sym, t.Elem())
    791 }
    792 
    793 // Statements which may be rendered with a simplestmt as init.
    794 func stmtwithinit(op Op) bool {
    795 	switch op {
    796 	case OIF, OFOR, OSWITCH:
    797 		return true
    798 	}
    799 
    800 	return false
    801 }
    802 
    803 func (n *Node) stmtfmt(s fmt.State) {
    804 	// some statements allow for an init, but at most one,
    805 	// but we may have an arbitrary number added, eg by typecheck
    806 	// and inlining. If it doesn't fit the syntax, emit an enclosing
    807 	// block starting with the init statements.
    808 
    809 	// if we can just say "for" n->ninit; ... then do so
    810 	simpleinit := n.Ninit.Len() == 1 && n.Ninit.First().Ninit.Len() == 0 && stmtwithinit(n.Op)
    811 
    812 	// otherwise, print the inits as separate statements
    813 	complexinit := n.Ninit.Len() != 0 && !simpleinit && (fmtmode != FErr)
    814 
    815 	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
    816 	extrablock := complexinit && stmtwithinit(n.Op)
    817 
    818 	if extrablock {
    819 		fmt.Fprint(s, "{")
    820 	}
    821 
    822 	if complexinit {
    823 		fmt.Fprintf(s, " %v; ", n.Ninit)
    824 	}
    825 
    826 	switch n.Op {
    827 	case ODCL:
    828 		fmt.Fprintf(s, "var %v %v", n.Left.Sym, n.Left.Type)
    829 
    830 	case ODCLFIELD:
    831 		if n.Left != nil {
    832 			fmt.Fprintf(s, "%v %v", n.Left, n.Right)
    833 		} else {
    834 			fmt.Fprintf(s, "%v", n.Right)
    835 		}
    836 
    837 	// Don't export "v = <N>" initializing statements, hope they're always
    838 	// preceded by the DCL which will be re-parsed and typechecked to reproduce
    839 	// the "v = <N>" again.
    840 	case OAS, OASWB:
    841 		if n.Colas && !complexinit {
    842 			fmt.Fprintf(s, "%v := %v", n.Left, n.Right)
    843 		} else {
    844 			fmt.Fprintf(s, "%v = %v", n.Left, n.Right)
    845 		}
    846 
    847 	case OASOP:
    848 		if n.Implicit {
    849 			if Op(n.Etype) == OADD {
    850 				fmt.Fprintf(s, "%v++", n.Left)
    851 			} else {
    852 				fmt.Fprintf(s, "%v--", n.Left)
    853 			}
    854 			break
    855 		}
    856 
    857 		fmt.Fprintf(s, "%v %#v= %v", n.Left, Op(n.Etype), n.Right)
    858 
    859 	case OAS2:
    860 		if n.Colas && !complexinit {
    861 			fmt.Fprintf(s, "%.v := %.v", n.List, n.Rlist)
    862 			break
    863 		}
    864 		fallthrough
    865 
    866 	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
    867 		fmt.Fprintf(s, "%.v = %.v", n.List, n.Rlist)
    868 
    869 	case ORETURN:
    870 		fmt.Fprintf(s, "return %.v", n.List)
    871 
    872 	case ORETJMP:
    873 		fmt.Fprintf(s, "retjmp %v", n.Sym)
    874 
    875 	case OPROC:
    876 		fmt.Fprintf(s, "go %v", n.Left)
    877 
    878 	case ODEFER:
    879 		fmt.Fprintf(s, "defer %v", n.Left)
    880 
    881 	case OIF:
    882 		if simpleinit {
    883 			fmt.Fprintf(s, "if %v; %v { %v }", n.Ninit.First(), n.Left, n.Nbody)
    884 		} else {
    885 			fmt.Fprintf(s, "if %v { %v }", n.Left, n.Nbody)
    886 		}
    887 		if n.Rlist.Len() != 0 {
    888 			fmt.Fprintf(s, " else { %v }", n.Rlist)
    889 		}
    890 
    891 	case OFOR:
    892 		if fmtmode == FErr { // TODO maybe only if FmtShort, same below
    893 			fmt.Fprint(s, "for loop")
    894 			break
    895 		}
    896 
    897 		fmt.Fprint(s, "for")
    898 		if simpleinit {
    899 			fmt.Fprintf(s, " %v;", n.Ninit.First())
    900 		} else if n.Right != nil {
    901 			fmt.Fprint(s, " ;")
    902 		}
    903 
    904 		if n.Left != nil {
    905 			fmt.Fprintf(s, " %v", n.Left)
    906 		}
    907 
    908 		if n.Right != nil {
    909 			fmt.Fprintf(s, "; %v", n.Right)
    910 		} else if simpleinit {
    911 			fmt.Fprint(s, ";")
    912 		}
    913 
    914 		fmt.Fprintf(s, " { %v }", n.Nbody)
    915 
    916 	case ORANGE:
    917 		if fmtmode == FErr {
    918 			fmt.Fprint(s, "for loop")
    919 			break
    920 		}
    921 
    922 		if n.List.Len() == 0 {
    923 			fmt.Fprintf(s, "for range %v { %v }", n.Right, n.Nbody)
    924 			break
    925 		}
    926 
    927 		fmt.Fprintf(s, "for %.v = range %v { %v }", n.List, n.Right, n.Nbody)
    928 
    929 	case OSELECT, OSWITCH:
    930 		if fmtmode == FErr {
    931 			fmt.Fprintf(s, "%v statement", n.Op)
    932 			break
    933 		}
    934 
    935 		fmt.Fprint(s, n.Op.GoString()) // %#v
    936 		if simpleinit {
    937 			fmt.Fprintf(s, " %v;", n.Ninit.First())
    938 		}
    939 		if n.Left != nil {
    940 			fmt.Fprintf(s, " %v ", n.Left)
    941 		}
    942 
    943 		fmt.Fprintf(s, " { %v }", n.List)
    944 
    945 	case OXCASE:
    946 		if n.List.Len() != 0 {
    947 			fmt.Fprintf(s, "case %.v", n.List)
    948 		} else {
    949 			fmt.Fprint(s, "default")
    950 		}
    951 		fmt.Fprintf(s, ": %v", n.Nbody)
    952 
    953 	case OCASE:
    954 		switch {
    955 		case n.Left != nil:
    956 			// single element
    957 			fmt.Fprintf(s, "case %v", n.Left)
    958 		case n.List.Len() > 0:
    959 			// range
    960 			if n.List.Len() != 2 {
    961 				Fatalf("bad OCASE list length %d", n.List.Len())
    962 			}
    963 			fmt.Fprintf(s, "case %v..%v", n.List.First(), n.List.Second())
    964 		default:
    965 			fmt.Fprint(s, "default")
    966 		}
    967 		fmt.Fprintf(s, ": %v", n.Nbody)
    968 
    969 	case OBREAK,
    970 		OCONTINUE,
    971 		OGOTO,
    972 		OFALL,
    973 		OXFALL:
    974 		if n.Left != nil {
    975 			fmt.Fprintf(s, "%#v %v", n.Op, n.Left)
    976 		} else {
    977 			fmt.Fprint(s, n.Op.GoString()) // %#v
    978 		}
    979 
    980 	case OEMPTY:
    981 		break
    982 
    983 	case OLABEL:
    984 		fmt.Fprintf(s, "%v: ", n.Left)
    985 	}
    986 
    987 	if extrablock {
    988 		fmt.Fprint(s, "}")
    989 	}
    990 }
    991 
    992 var opprec = []int{
    993 	OALIGNOF:      8,
    994 	OAPPEND:       8,
    995 	OARRAYBYTESTR: 8,
    996 	OARRAYLIT:     8,
    997 	OSLICELIT:     8,
    998 	OARRAYRUNESTR: 8,
    999 	OCALLFUNC:     8,
   1000 	OCALLINTER:    8,
   1001 	OCALLMETH:     8,
   1002 	OCALL:         8,
   1003 	OCAP:          8,
   1004 	OCLOSE:        8,
   1005 	OCONVIFACE:    8,
   1006 	OCONVNOP:      8,
   1007 	OCONV:         8,
   1008 	OCOPY:         8,
   1009 	ODELETE:       8,
   1010 	OGETG:         8,
   1011 	OLEN:          8,
   1012 	OLITERAL:      8,
   1013 	OMAKESLICE:    8,
   1014 	OMAKE:         8,
   1015 	OMAPLIT:       8,
   1016 	ONAME:         8,
   1017 	ONEW:          8,
   1018 	ONONAME:       8,
   1019 	OOFFSETOF:     8,
   1020 	OPACK:         8,
   1021 	OPANIC:        8,
   1022 	OPAREN:        8,
   1023 	OPRINTN:       8,
   1024 	OPRINT:        8,
   1025 	ORUNESTR:      8,
   1026 	OSIZEOF:       8,
   1027 	OSTRARRAYBYTE: 8,
   1028 	OSTRARRAYRUNE: 8,
   1029 	OSTRUCTLIT:    8,
   1030 	OTARRAY:       8,
   1031 	OTCHAN:        8,
   1032 	OTFUNC:        8,
   1033 	OTINTER:       8,
   1034 	OTMAP:         8,
   1035 	OTSTRUCT:      8,
   1036 	OINDEXMAP:     8,
   1037 	OINDEX:        8,
   1038 	OSLICE:        8,
   1039 	OSLICESTR:     8,
   1040 	OSLICEARR:     8,
   1041 	OSLICE3:       8,
   1042 	OSLICE3ARR:    8,
   1043 	ODOTINTER:     8,
   1044 	ODOTMETH:      8,
   1045 	ODOTPTR:       8,
   1046 	ODOTTYPE2:     8,
   1047 	ODOTTYPE:      8,
   1048 	ODOT:          8,
   1049 	OXDOT:         8,
   1050 	OCALLPART:     8,
   1051 	OPLUS:         7,
   1052 	ONOT:          7,
   1053 	OCOM:          7,
   1054 	OMINUS:        7,
   1055 	OADDR:         7,
   1056 	OIND:          7,
   1057 	ORECV:         7,
   1058 	OMUL:          6,
   1059 	ODIV:          6,
   1060 	OMOD:          6,
   1061 	OLSH:          6,
   1062 	ORSH:          6,
   1063 	OAND:          6,
   1064 	OANDNOT:       6,
   1065 	OADD:          5,
   1066 	OSUB:          5,
   1067 	OOR:           5,
   1068 	OXOR:          5,
   1069 	OEQ:           4,
   1070 	OLT:           4,
   1071 	OLE:           4,
   1072 	OGE:           4,
   1073 	OGT:           4,
   1074 	ONE:           4,
   1075 	OCMPSTR:       4,
   1076 	OCMPIFACE:     4,
   1077 	OSEND:         3,
   1078 	OANDAND:       2,
   1079 	OOROR:         1,
   1080 	// Statements handled by stmtfmt
   1081 	OAS:         -1,
   1082 	OAS2:        -1,
   1083 	OAS2DOTTYPE: -1,
   1084 	OAS2FUNC:    -1,
   1085 	OAS2MAPR:    -1,
   1086 	OAS2RECV:    -1,
   1087 	OASOP:       -1,
   1088 	OBREAK:      -1,
   1089 	OCASE:       -1,
   1090 	OCONTINUE:   -1,
   1091 	ODCL:        -1,
   1092 	ODCLFIELD:   -1,
   1093 	ODEFER:      -1,
   1094 	OEMPTY:      -1,
   1095 	OFALL:       -1,
   1096 	OFOR:        -1,
   1097 	OGOTO:       -1,
   1098 	OIF:         -1,
   1099 	OLABEL:      -1,
   1100 	OPROC:       -1,
   1101 	ORANGE:      -1,
   1102 	ORETURN:     -1,
   1103 	OSELECT:     -1,
   1104 	OSWITCH:     -1,
   1105 	OXCASE:      -1,
   1106 	OXFALL:      -1,
   1107 	OEND:        0,
   1108 }
   1109 
   1110 func (n *Node) exprfmt(s fmt.State, prec int) {
   1111 	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
   1112 		n = n.Left
   1113 	}
   1114 
   1115 	if n == nil {
   1116 		fmt.Fprint(s, "<N>")
   1117 		return
   1118 	}
   1119 
   1120 	nprec := opprec[n.Op]
   1121 	if n.Op == OTYPE && n.Sym != nil {
   1122 		nprec = 8
   1123 	}
   1124 
   1125 	if prec > nprec {
   1126 		fmt.Fprintf(s, "(%v)", n)
   1127 		return
   1128 	}
   1129 
   1130 	switch n.Op {
   1131 	case OPAREN:
   1132 		fmt.Fprintf(s, "(%v)", n.Left)
   1133 
   1134 	case ODDDARG:
   1135 		fmt.Fprint(s, "... argument")
   1136 
   1137 	case OLITERAL: // this is a bit of a mess
   1138 		if fmtmode == FErr {
   1139 			if n.Orig != nil && n.Orig != n {
   1140 				n.Orig.exprfmt(s, prec)
   1141 				return
   1142 			}
   1143 			if n.Sym != nil {
   1144 				fmt.Fprint(s, n.Sym.String())
   1145 				return
   1146 			}
   1147 		}
   1148 		if n.Val().Ctype() == CTNIL && n.Orig != nil && n.Orig != n {
   1149 			n.Orig.exprfmt(s, prec)
   1150 			return
   1151 		}
   1152 		if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != idealbool && n.Type != idealstring {
   1153 			// Need parens when type begins with what might
   1154 			// be misinterpreted as a unary operator: * or <-.
   1155 			if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == Crecv) {
   1156 				fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Val())
   1157 				return
   1158 			} else {
   1159 				fmt.Fprintf(s, "%v(%v)", n.Type, n.Val())
   1160 				return
   1161 			}
   1162 		}
   1163 
   1164 		fmt.Fprintf(s, "%v", n.Val())
   1165 
   1166 	// Special case: name used as local variable in export.
   1167 	// _ becomes ~b%d internally; print as _ for export
   1168 	case ONAME:
   1169 		if fmtmode == FErr && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
   1170 			fmt.Fprint(s, "_")
   1171 			return
   1172 		}
   1173 		fallthrough
   1174 	case OPACK, ONONAME:
   1175 		fmt.Fprint(s, n.Sym.String())
   1176 
   1177 	case OTYPE:
   1178 		if n.Type == nil && n.Sym != nil {
   1179 			fmt.Fprint(s, n.Sym.String())
   1180 			return
   1181 		}
   1182 		fmt.Fprintf(s, "%v", n.Type)
   1183 
   1184 	case OTARRAY:
   1185 		if n.Left != nil {
   1186 			fmt.Fprintf(s, "[]%v", n.Left)
   1187 			return
   1188 		}
   1189 		fmt.Fprintf(s, "[]%v", n.Right) // happens before typecheck
   1190 
   1191 	case OTMAP:
   1192 		fmt.Fprintf(s, "map[%v]%v", n.Left, n.Right)
   1193 
   1194 	case OTCHAN:
   1195 		switch ChanDir(n.Etype) {
   1196 		case Crecv:
   1197 			fmt.Fprintf(s, "<-chan %v", n.Left)
   1198 
   1199 		case Csend:
   1200 			fmt.Fprintf(s, "chan<- %v", n.Left)
   1201 
   1202 		default:
   1203 			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv {
   1204 				fmt.Fprintf(s, "chan (%v)", n.Left)
   1205 			} else {
   1206 				fmt.Fprintf(s, "chan %v", n.Left)
   1207 			}
   1208 		}
   1209 
   1210 	case OTSTRUCT:
   1211 		fmt.Fprint(s, "<struct>")
   1212 
   1213 	case OTINTER:
   1214 		fmt.Fprint(s, "<inter>")
   1215 
   1216 	case OTFUNC:
   1217 		fmt.Fprint(s, "<func>")
   1218 
   1219 	case OCLOSURE:
   1220 		if fmtmode == FErr {
   1221 			fmt.Fprint(s, "func literal")
   1222 			return
   1223 		}
   1224 		if n.Nbody.Len() != 0 {
   1225 			fmt.Fprintf(s, "%v { %v }", n.Type, n.Nbody)
   1226 			return
   1227 		}
   1228 		fmt.Fprintf(s, "%v { %v }", n.Type, n.Func.Closure.Nbody)
   1229 
   1230 	case OCOMPLIT:
   1231 		ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && n.Right.Type.IsPtr()
   1232 		if fmtmode == FErr {
   1233 			if n.Right != nil && n.Right.Type != nil && !n.Implicit {
   1234 				if ptrlit {
   1235 					fmt.Fprintf(s, "&%v literal", n.Right.Type.Elem())
   1236 					return
   1237 				} else {
   1238 					fmt.Fprintf(s, "%v literal", n.Right.Type)
   1239 					return
   1240 				}
   1241 			}
   1242 
   1243 			fmt.Fprint(s, "composite literal")
   1244 			return
   1245 		}
   1246 		fmt.Fprintf(s, "(%v{ %.v })", n.Right, n.List)
   1247 
   1248 	case OPTRLIT:
   1249 		fmt.Fprintf(s, "&%v", n.Left)
   1250 
   1251 	case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
   1252 		if fmtmode == FErr {
   1253 			fmt.Fprintf(s, "%v literal", n.Type)
   1254 			return
   1255 		}
   1256 		fmt.Fprintf(s, "(%v{ %.v })", n.Type, n.List)
   1257 
   1258 	case OKEY:
   1259 		if n.Left != nil && n.Right != nil {
   1260 			fmt.Fprintf(s, "%v:%v", n.Left, n.Right)
   1261 			return
   1262 		}
   1263 
   1264 		if n.Left == nil && n.Right != nil {
   1265 			fmt.Fprintf(s, ":%v", n.Right)
   1266 			return
   1267 		}
   1268 		if n.Left != nil && n.Right == nil {
   1269 			fmt.Fprintf(s, "%v:", n.Left)
   1270 			return
   1271 		}
   1272 		fmt.Fprint(s, ":")
   1273 
   1274 	case OSTRUCTKEY:
   1275 		fmt.Fprintf(s, "%v:%v", n.Sym, n.Left)
   1276 
   1277 	case OCALLPART:
   1278 		n.Left.exprfmt(s, nprec)
   1279 		if n.Right == nil || n.Right.Sym == nil {
   1280 			fmt.Fprint(s, ".<nil>")
   1281 			return
   1282 		}
   1283 		fmt.Fprintf(s, ".%0S", n.Right.Sym)
   1284 
   1285 	case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
   1286 		n.Left.exprfmt(s, nprec)
   1287 		if n.Sym == nil {
   1288 			fmt.Fprint(s, ".<nil>")
   1289 			return
   1290 		}
   1291 		fmt.Fprintf(s, ".%0S", n.Sym)
   1292 
   1293 	case ODOTTYPE, ODOTTYPE2:
   1294 		n.Left.exprfmt(s, nprec)
   1295 		if n.Right != nil {
   1296 			fmt.Fprintf(s, ".(%v)", n.Right)
   1297 			return
   1298 		}
   1299 		fmt.Fprintf(s, ".(%v)", n.Type)
   1300 
   1301 	case OINDEX, OINDEXMAP:
   1302 		n.Left.exprfmt(s, nprec)
   1303 		fmt.Fprintf(s, "[%v]", n.Right)
   1304 
   1305 	case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
   1306 		n.Left.exprfmt(s, nprec)
   1307 		fmt.Fprint(s, "[")
   1308 		low, high, max := n.SliceBounds()
   1309 		if low != nil {
   1310 			fmt.Fprint(s, low.String())
   1311 		}
   1312 		fmt.Fprint(s, ":")
   1313 		if high != nil {
   1314 			fmt.Fprint(s, high.String())
   1315 		}
   1316 		if n.Op.IsSlice3() {
   1317 			fmt.Fprint(s, ":")
   1318 			if max != nil {
   1319 				fmt.Fprint(s, max.String())
   1320 			}
   1321 		}
   1322 		fmt.Fprint(s, "]")
   1323 
   1324 	case OCOPY, OCOMPLEX:
   1325 		fmt.Fprintf(s, "%#v(%v, %v)", n.Op, n.Left, n.Right)
   1326 
   1327 	case OCONV,
   1328 		OCONVIFACE,
   1329 		OCONVNOP,
   1330 		OARRAYBYTESTR,
   1331 		OARRAYRUNESTR,
   1332 		OSTRARRAYBYTE,
   1333 		OSTRARRAYRUNE,
   1334 		ORUNESTR:
   1335 		if n.Type == nil || n.Type.Sym == nil {
   1336 			fmt.Fprintf(s, "(%v)(%v)", n.Type, n.Left)
   1337 			return
   1338 		}
   1339 		if n.Left != nil {
   1340 			fmt.Fprintf(s, "%v(%v)", n.Type, n.Left)
   1341 			return
   1342 		}
   1343 		fmt.Fprintf(s, "%v(%.v)", n.Type, n.List)
   1344 
   1345 	case OREAL,
   1346 		OIMAG,
   1347 		OAPPEND,
   1348 		OCAP,
   1349 		OCLOSE,
   1350 		ODELETE,
   1351 		OLEN,
   1352 		OMAKE,
   1353 		ONEW,
   1354 		OPANIC,
   1355 		ORECOVER,
   1356 		OALIGNOF,
   1357 		OOFFSETOF,
   1358 		OSIZEOF,
   1359 		OPRINT,
   1360 		OPRINTN:
   1361 		if n.Left != nil {
   1362 			fmt.Fprintf(s, "%#v(%v)", n.Op, n.Left)
   1363 			return
   1364 		}
   1365 		if n.Isddd {
   1366 			fmt.Fprintf(s, "%#v(%.v...)", n.Op, n.List)
   1367 			return
   1368 		}
   1369 		fmt.Fprintf(s, "%#v(%.v)", n.Op, n.List)
   1370 
   1371 	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
   1372 		n.Left.exprfmt(s, nprec)
   1373 		if n.Isddd {
   1374 			fmt.Fprintf(s, "(%.v...)", n.List)
   1375 			return
   1376 		}
   1377 		fmt.Fprintf(s, "(%.v)", n.List)
   1378 
   1379 	case OMAKEMAP, OMAKECHAN, OMAKESLICE:
   1380 		if n.List.Len() != 0 { // pre-typecheck
   1381 			fmt.Fprintf(s, "make(%v, %.v)", n.Type, n.List)
   1382 			return
   1383 		}
   1384 		if n.Right != nil {
   1385 			fmt.Fprintf(s, "make(%v, %v, %v)", n.Type, n.Left, n.Right)
   1386 			return
   1387 		}
   1388 		if n.Left != nil && (n.Op == OMAKESLICE || !n.Left.Type.IsUntyped()) {
   1389 			fmt.Fprintf(s, "make(%v, %v)", n.Type, n.Left)
   1390 			return
   1391 		}
   1392 		fmt.Fprintf(s, "make(%v)", n.Type)
   1393 
   1394 		// Unary
   1395 	case OPLUS,
   1396 		OMINUS,
   1397 		OADDR,
   1398 		OCOM,
   1399 		OIND,
   1400 		ONOT,
   1401 		ORECV:
   1402 		fmt.Fprint(s, n.Op.GoString()) // %#v
   1403 		if n.Left.Op == n.Op {
   1404 			fmt.Fprint(s, " ")
   1405 		}
   1406 		n.Left.exprfmt(s, nprec+1)
   1407 
   1408 		// Binary
   1409 	case OADD,
   1410 		OAND,
   1411 		OANDAND,
   1412 		OANDNOT,
   1413 		ODIV,
   1414 		OEQ,
   1415 		OGE,
   1416 		OGT,
   1417 		OLE,
   1418 		OLT,
   1419 		OLSH,
   1420 		OMOD,
   1421 		OMUL,
   1422 		ONE,
   1423 		OOR,
   1424 		OOROR,
   1425 		ORSH,
   1426 		OSEND,
   1427 		OSUB,
   1428 		OXOR:
   1429 		n.Left.exprfmt(s, nprec)
   1430 		fmt.Fprintf(s, " %#v ", n.Op)
   1431 		n.Right.exprfmt(s, nprec+1)
   1432 
   1433 	case OADDSTR:
   1434 		i := 0
   1435 		for _, n1 := range n.List.Slice() {
   1436 			if i != 0 {
   1437 				fmt.Fprint(s, " + ")
   1438 			}
   1439 			n1.exprfmt(s, nprec)
   1440 			i++
   1441 		}
   1442 
   1443 	case OCMPSTR, OCMPIFACE:
   1444 		n.Left.exprfmt(s, nprec)
   1445 		// TODO(marvin): Fix Node.EType type union.
   1446 		fmt.Fprintf(s, " %#v ", Op(n.Etype))
   1447 		n.Right.exprfmt(s, nprec+1)
   1448 
   1449 	default:
   1450 		fmt.Fprintf(s, "<node %v>", n.Op)
   1451 	}
   1452 }
   1453 
   1454 func (n *Node) nodefmt(s fmt.State, flag FmtFlag) {
   1455 	t := n.Type
   1456 
   1457 	// we almost always want the original, except in export mode for literals
   1458 	// this saves the importer some work, and avoids us having to redo some
   1459 	// special casing for package unsafe
   1460 	if n.Op != OLITERAL && n.Orig != nil {
   1461 		n = n.Orig
   1462 	}
   1463 
   1464 	if flag&FmtLong != 0 && t != nil {
   1465 		if t.Etype == TNIL {
   1466 			fmt.Fprint(s, "nil")
   1467 		} else {
   1468 			fmt.Fprintf(s, "%v (type %v)", n, t)
   1469 		}
   1470 		return
   1471 	}
   1472 
   1473 	// TODO inlining produces expressions with ninits. we can't print these yet.
   1474 
   1475 	if opprec[n.Op] < 0 {
   1476 		n.stmtfmt(s)
   1477 		return
   1478 	}
   1479 
   1480 	n.exprfmt(s, 0)
   1481 }
   1482 
   1483 func (n *Node) nodedump(s fmt.State, flag FmtFlag) {
   1484 	if n == nil {
   1485 		return
   1486 	}
   1487 
   1488 	recur := flag&FmtShort == 0
   1489 
   1490 	if recur {
   1491 		indent(s)
   1492 		if dumpdepth > 10 {
   1493 			fmt.Fprint(s, "...")
   1494 			return
   1495 		}
   1496 
   1497 		if n.Ninit.Len() != 0 {
   1498 			fmt.Fprintf(s, "%v-init%v", n.Op, n.Ninit)
   1499 			indent(s)
   1500 		}
   1501 	}
   1502 
   1503 	switch n.Op {
   1504 	default:
   1505 		fmt.Fprintf(s, "%v%j", n.Op, n)
   1506 
   1507 	case OINDREGSP:
   1508 		fmt.Fprintf(s, "%v-SP%j", n.Op, n)
   1509 
   1510 	case OLITERAL:
   1511 		fmt.Fprintf(s, "%v-%v%j", n.Op, n.Val(), n)
   1512 
   1513 	case ONAME, ONONAME:
   1514 		if n.Sym != nil {
   1515 			fmt.Fprintf(s, "%v-%v%j", n.Op, n.Sym, n)
   1516 		} else {
   1517 			fmt.Fprintf(s, "%v%j", n.Op, n)
   1518 		}
   1519 		if recur && n.Type == nil && n.Name != nil && n.Name.Param != nil && n.Name.Param.Ntype != nil {
   1520 			indent(s)
   1521 			fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
   1522 		}
   1523 
   1524 	case OASOP:
   1525 		fmt.Fprintf(s, "%v-%v%j", n.Op, Op(n.Etype), n)
   1526 
   1527 	case OTYPE:
   1528 		fmt.Fprintf(s, "%v %v%j type=%v", n.Op, n.Sym, n, n.Type)
   1529 		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
   1530 			indent(s)
   1531 			fmt.Fprintf(s, "%v-ntype%v", n.Op, n.Name.Param.Ntype)
   1532 		}
   1533 	}
   1534 
   1535 	if n.Sym != nil && n.Op != ONAME {
   1536 		fmt.Fprintf(s, " %v", n.Sym)
   1537 	}
   1538 
   1539 	if n.Type != nil {
   1540 		fmt.Fprintf(s, " %v", n.Type)
   1541 	}
   1542 
   1543 	if recur {
   1544 		if n.Left != nil {
   1545 			fmt.Fprintf(s, "%v", n.Left)
   1546 		}
   1547 		if n.Right != nil {
   1548 			fmt.Fprintf(s, "%v", n.Right)
   1549 		}
   1550 		if n.List.Len() != 0 {
   1551 			indent(s)
   1552 			fmt.Fprintf(s, "%v-list%v", n.Op, n.List)
   1553 		}
   1554 
   1555 		if n.Rlist.Len() != 0 {
   1556 			indent(s)
   1557 			fmt.Fprintf(s, "%v-rlist%v", n.Op, n.Rlist)
   1558 		}
   1559 
   1560 		if n.Nbody.Len() != 0 {
   1561 			indent(s)
   1562 			fmt.Fprintf(s, "%v-body%v", n.Op, n.Nbody)
   1563 		}
   1564 	}
   1565 }
   1566 
   1567 // "%S" suppresses qualifying with package
   1568 func (s *Sym) Format(f fmt.State, verb rune) {
   1569 	switch verb {
   1570 	case 'v', 'S':
   1571 		fmt.Fprint(f, s.sconv(fmtFlag(f, verb)))
   1572 
   1573 	default:
   1574 		fmt.Fprintf(f, "%%!%c(*Sym=%p)", verb, s)
   1575 	}
   1576 }
   1577 
   1578 func (s *Sym) String() string {
   1579 	return s.sconv(0)
   1580 }
   1581 
   1582 // See #16897 before changing the implementation of sconv.
   1583 func (s *Sym) sconv(flag FmtFlag) string {
   1584 	if flag&FmtLong != 0 {
   1585 		panic("linksymfmt")
   1586 	}
   1587 
   1588 	if s == nil {
   1589 		return "<S>"
   1590 	}
   1591 
   1592 	if s.Name == "_" {
   1593 		return "_"
   1594 	}
   1595 
   1596 	sf := flag
   1597 	sm := setfmode(&flag)
   1598 	str := s.symfmt(flag)
   1599 	flag = sf
   1600 	fmtmode = sm
   1601 	return str
   1602 }
   1603 
   1604 func (t *Type) String() string {
   1605 	return t.tconv(0)
   1606 }
   1607 
   1608 func fldconv(f *Field, flag FmtFlag) string {
   1609 	if f == nil {
   1610 		return "<T>"
   1611 	}
   1612 
   1613 	sf := flag
   1614 	sm := setfmode(&flag)
   1615 
   1616 	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
   1617 		fmtpkgpfx++
   1618 	}
   1619 	if fmtpkgpfx != 0 {
   1620 		flag |= FmtUnsigned
   1621 	}
   1622 
   1623 	var name string
   1624 	if flag&FmtShort == 0 {
   1625 		s := f.Sym
   1626 
   1627 		// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
   1628 		// ~r%d is a (formerly) unnamed result.
   1629 		if fmtmode == FErr && f.Nname != nil {
   1630 			if f.Nname.Orig != nil {
   1631 				s = f.Nname.Orig.Sym
   1632 				if s != nil && s.Name[0] == '~' {
   1633 					if s.Name[1] == 'r' { // originally an unnamed result
   1634 						s = nil
   1635 					} else if s.Name[1] == 'b' { // originally the blank identifier _
   1636 						s = lookup("_")
   1637 					}
   1638 				}
   1639 			} else {
   1640 				s = nil
   1641 			}
   1642 		}
   1643 
   1644 		if s != nil && f.Embedded == 0 {
   1645 			if f.Funarg != FunargNone {
   1646 				name = f.Nname.String()
   1647 			} else if flag&FmtLong != 0 {
   1648 				name = fmt.Sprintf("%0S", s)
   1649 				if !exportname(name) && flag&FmtUnsigned == 0 {
   1650 					name = s.String() // qualify non-exported names (used on structs, not on funarg)
   1651 				}
   1652 			} else {
   1653 				name = s.String()
   1654 			}
   1655 		}
   1656 	}
   1657 
   1658 	var typ string
   1659 	if f.Isddd {
   1660 		typ = fmt.Sprintf("...%v", f.Type.Elem())
   1661 	} else {
   1662 		typ = fmt.Sprintf("%v", f.Type)
   1663 	}
   1664 
   1665 	str := typ
   1666 	if name != "" {
   1667 		str = name + " " + typ
   1668 	}
   1669 
   1670 	if flag&FmtShort == 0 && f.Funarg == FunargNone && f.Note != "" {
   1671 		str += " " + strconv.Quote(f.Note)
   1672 	}
   1673 
   1674 	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
   1675 		fmtpkgpfx--
   1676 	}
   1677 
   1678 	flag = sf
   1679 	fmtmode = sm
   1680 	return str
   1681 }
   1682 
   1683 // "%L"  print definition, not name
   1684 // "%S"  omit 'func' and receiver from function types, short type names
   1685 // "% v" package name, not prefix (FTypeId mode, sticky)
   1686 func (t *Type) Format(s fmt.State, verb rune) {
   1687 	switch verb {
   1688 	case 'v', 'S', 'L':
   1689 		fmt.Fprint(s, t.tconv(fmtFlag(s, verb)))
   1690 
   1691 	default:
   1692 		fmt.Fprintf(s, "%%!%c(*Type=%p)", verb, t)
   1693 	}
   1694 }
   1695 
   1696 // See #16897 before changing the implementation of tconv.
   1697 func (t *Type) tconv(flag FmtFlag) string {
   1698 	if t == nil {
   1699 		return "<T>"
   1700 	}
   1701 
   1702 	if t.Trecur > 4 {
   1703 		return "<...>"
   1704 	}
   1705 
   1706 	t.Trecur++
   1707 	sf := flag
   1708 	sm := setfmode(&flag)
   1709 
   1710 	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
   1711 		fmtpkgpfx++
   1712 	}
   1713 	if fmtpkgpfx != 0 {
   1714 		flag |= FmtUnsigned
   1715 	}
   1716 
   1717 	str := t.typefmt(flag)
   1718 
   1719 	if fmtmode == FTypeId && (sf&FmtUnsigned != 0) {
   1720 		fmtpkgpfx--
   1721 	}
   1722 
   1723 	flag = sf
   1724 	fmtmode = sm
   1725 	t.Trecur--
   1726 	return str
   1727 }
   1728 
   1729 func (n *Node) String() string {
   1730 	return fmt.Sprint(n)
   1731 }
   1732 
   1733 // "%L"  suffix with "(type %T)" where possible
   1734 // "%+S" in debug mode, don't recurse, no multiline output
   1735 func (n *Node) Nconv(s fmt.State, flag FmtFlag) {
   1736 	if n == nil {
   1737 		fmt.Fprint(s, "<N>")
   1738 		return
   1739 	}
   1740 
   1741 	sf := flag
   1742 	sm := setfmode(&flag)
   1743 
   1744 	switch fmtmode {
   1745 	case FErr:
   1746 		n.nodefmt(s, flag)
   1747 
   1748 	case FDbg:
   1749 		dumpdepth++
   1750 		n.nodedump(s, flag)
   1751 		dumpdepth--
   1752 
   1753 	default:
   1754 		Fatalf("unhandled %%N mode: %d", fmtmode)
   1755 	}
   1756 
   1757 	flag = sf
   1758 	fmtmode = sm
   1759 }
   1760 
   1761 func (l Nodes) Format(s fmt.State, verb rune) {
   1762 	switch verb {
   1763 	case 'v':
   1764 		l.hconv(s, fmtFlag(s, verb))
   1765 
   1766 	default:
   1767 		fmt.Fprintf(s, "%%!%c(Nodes)", verb)
   1768 	}
   1769 }
   1770 
   1771 func (n Nodes) String() string {
   1772 	return fmt.Sprint(n)
   1773 }
   1774 
   1775 // Flags: all those of %N plus '.': separate with comma's instead of semicolons.
   1776 func (l Nodes) hconv(s fmt.State, flag FmtFlag) {
   1777 	if l.Len() == 0 && fmtmode == FDbg {
   1778 		fmt.Fprint(s, "<nil>")
   1779 		return
   1780 	}
   1781 
   1782 	sf := flag
   1783 	sm := setfmode(&flag)
   1784 	sep := "; "
   1785 	if fmtmode == FDbg {
   1786 		sep = "\n"
   1787 	} else if flag&FmtComma != 0 {
   1788 		sep = ", "
   1789 	}
   1790 
   1791 	for i, n := range l.Slice() {
   1792 		fmt.Fprint(s, n)
   1793 		if i+1 < l.Len() {
   1794 			fmt.Fprint(s, sep)
   1795 		}
   1796 	}
   1797 
   1798 	flag = sf
   1799 	fmtmode = sm
   1800 }
   1801 
   1802 func dumplist(s string, l Nodes) {
   1803 	fmt.Printf("%s%+v\n", s, l)
   1804 }
   1805 
   1806 func Dump(s string, n *Node) {
   1807 	fmt.Printf("%s [%p]%+v\n", s, n, n)
   1808 }
   1809 
   1810 // TODO(gri) make variable local somehow
   1811 var dumpdepth int
   1812 
   1813 // indent prints indentation to s.
   1814 func indent(s fmt.State) {
   1815 	fmt.Fprint(s, "\n")
   1816 	for i := 0; i < dumpdepth; i++ {
   1817 		fmt.Fprint(s, ".   ")
   1818 	}
   1819 }
   1820