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