github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/swt.go (about)

     1  // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/swt.go
     2  
     3  // Copyright 2009 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  package gc
     8  
     9  import (
    10  	"rsc.io/tmp/bootstrap/internal/obj"
    11  	"fmt"
    12  	"sort"
    13  	"strconv"
    14  )
    15  
    16  const (
    17  	// expression switch
    18  	switchKindExpr  = iota // switch a {...} or switch 5 {...}
    19  	switchKindTrue         // switch true {...} or switch {...}
    20  	switchKindFalse        // switch false {...}
    21  
    22  	// type switch
    23  	switchKindType // switch a.(type) {...}
    24  )
    25  
    26  const (
    27  	caseKindDefault = iota // default:
    28  
    29  	// expression switch
    30  	caseKindExprConst // case 5:
    31  	caseKindExprVar   // case x:
    32  
    33  	// type switch
    34  	caseKindTypeNil   // case nil:
    35  	caseKindTypeConst // case time.Time: (concrete type, has type hash)
    36  	caseKindTypeVar   // case io.Reader: (interface type)
    37  )
    38  
    39  const binarySearchMin = 4 // minimum number of cases for binary search
    40  
    41  // An exprSwitch walks an expression switch.
    42  type exprSwitch struct {
    43  	exprname *Node // node for the expression being switched on
    44  	kind     int   // kind of switch statement (switchKind*)
    45  }
    46  
    47  // A typeSwitch walks a type switch.
    48  type typeSwitch struct {
    49  	hashname *Node // node for the hash of the type of the variable being switched on
    50  	facename *Node // node for the concrete type of the variable being switched on
    51  	okname   *Node // boolean node used for comma-ok type assertions
    52  }
    53  
    54  // A caseClause is a single case clause in a switch statement.
    55  type caseClause struct {
    56  	node    *Node  // points at case statement
    57  	ordinal int    // position in switch
    58  	hash    uint32 // hash of a type switch
    59  	typ     uint8  // type of case
    60  }
    61  
    62  // typecheckswitch typechecks a switch statement.
    63  func typecheckswitch(n *Node) {
    64  	lno := int(lineno)
    65  	typechecklist(n.Ninit, Etop)
    66  
    67  	var nilonly string
    68  	var top int
    69  	var t *Type
    70  
    71  	if n.Ntest != nil && n.Ntest.Op == OTYPESW {
    72  		// type switch
    73  		top = Etype
    74  		typecheck(&n.Ntest.Right, Erv)
    75  		t = n.Ntest.Right.Type
    76  		if t != nil && t.Etype != TINTER {
    77  			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Ntest.Right, obj.FmtLong))
    78  		}
    79  	} else {
    80  		// expression switch
    81  		top = Erv
    82  		if n.Ntest != nil {
    83  			typecheck(&n.Ntest, Erv)
    84  			defaultlit(&n.Ntest, nil)
    85  			t = n.Ntest.Type
    86  		} else {
    87  			t = Types[TBOOL]
    88  		}
    89  		if t != nil {
    90  			var badtype *Type
    91  			switch {
    92  			case !okforeq[t.Etype]:
    93  				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
    94  			case t.Etype == TARRAY && !Isfixedarray(t):
    95  				nilonly = "slice"
    96  			case t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ:
    97  				Yyerror("cannot switch on %v", Nconv(n.Ntest, obj.FmtLong))
    98  			case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ:
    99  				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Ntest, obj.FmtLong), badtype)
   100  			case t.Etype == TFUNC:
   101  				nilonly = "func"
   102  			case t.Etype == TMAP:
   103  				nilonly = "map"
   104  			}
   105  		}
   106  	}
   107  
   108  	n.Type = t
   109  
   110  	var def *Node
   111  	var ll *NodeList
   112  	for l := n.List; l != nil; l = l.Next {
   113  		ncase := l.N
   114  		setlineno(n)
   115  		if ncase.List == nil {
   116  			// default
   117  			if def != nil {
   118  				Yyerror("multiple defaults in switch (first at %v)", def.Line())
   119  			} else {
   120  				def = ncase
   121  			}
   122  		} else {
   123  			for ll = ncase.List; ll != nil; ll = ll.Next {
   124  				setlineno(ll.N)
   125  				typecheck(&ll.N, Erv|Etype)
   126  				if ll.N.Type == nil || t == nil {
   127  					continue
   128  				}
   129  				setlineno(ncase)
   130  				switch top {
   131  				// expression switch
   132  				case Erv:
   133  					defaultlit(&ll.N, t)
   134  					switch {
   135  					case ll.N.Op == OTYPE:
   136  						Yyerror("type %v is not an expression", ll.N.Type)
   137  					case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0:
   138  						if n.Ntest != nil {
   139  							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", ll.N, n.Ntest, ll.N.Type, t)
   140  						} else {
   141  							Yyerror("invalid case %v in switch (mismatched types %v and bool)", ll.N, ll.N.Type)
   142  						}
   143  					case nilonly != "" && !Isconst(ll.N, CTNIL):
   144  						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", ll.N, nilonly, n.Ntest)
   145  					}
   146  
   147  				// type switch
   148  				case Etype:
   149  					var missing, have *Type
   150  					var ptr int
   151  					switch {
   152  					case ll.N.Op == OLITERAL && Istype(ll.N.Type, TNIL):
   153  					case ll.N.Op != OTYPE && ll.N.Type != nil: // should this be ||?
   154  						Yyerror("%v is not a type", Nconv(ll.N, obj.FmtLong))
   155  						// reset to original type
   156  						ll.N = n.Ntest.Right
   157  					case ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr):
   158  						if have != nil && missing.Broke == 0 && have.Broke == 0 {
   159  							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Ntest.Right, obj.FmtLong), ll.N.Type, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort), missing.Sym, Tconv(missing.Type, obj.FmtShort))
   160  						} else if missing.Broke == 0 {
   161  							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Ntest.Right, obj.FmtLong), ll.N.Type, missing.Sym)
   162  						}
   163  					}
   164  				}
   165  			}
   166  		}
   167  
   168  		if top == Etype && n.Type != nil {
   169  			ll = ncase.List
   170  			nvar := ncase.Nname
   171  			if nvar != nil {
   172  				if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
   173  					// single entry type switch
   174  					nvar.Ntype = typenod(ll.N.Type)
   175  				} else {
   176  					// multiple entry type switch or default
   177  					nvar.Ntype = typenod(n.Type)
   178  				}
   179  
   180  				typecheck(&nvar, Erv|Easgn)
   181  				ncase.Nname = nvar
   182  			}
   183  		}
   184  
   185  		typechecklist(ncase.Nbody, Etop)
   186  	}
   187  
   188  	lineno = int32(lno)
   189  }
   190  
   191  // walkswitch walks a switch statement.
   192  func walkswitch(sw *Node) {
   193  	// convert switch {...} to switch true {...}
   194  	if sw.Ntest == nil {
   195  		sw.Ntest = Nodbool(true)
   196  		typecheck(&sw.Ntest, Erv)
   197  	}
   198  
   199  	if sw.Ntest.Op == OTYPESW {
   200  		var s typeSwitch
   201  		s.walk(sw)
   202  	} else {
   203  		var s exprSwitch
   204  		s.walk(sw)
   205  	}
   206  
   207  	// Discard old AST elements. They can confuse racewalk.
   208  	sw.Ntest = nil
   209  	sw.List = nil
   210  }
   211  
   212  // walk generates an AST implementing sw.
   213  // sw is an expression switch.
   214  // The AST is generally of the form of a linear
   215  // search using if..goto, although binary search
   216  // is used with long runs of constants.
   217  func (s *exprSwitch) walk(sw *Node) {
   218  	casebody(sw, nil)
   219  
   220  	s.kind = switchKindExpr
   221  	if Isconst(sw.Ntest, CTBOOL) {
   222  		s.kind = switchKindTrue
   223  		if !sw.Ntest.Val.U.Bval {
   224  			s.kind = switchKindFalse
   225  		}
   226  	}
   227  
   228  	walkexpr(&sw.Ntest, &sw.Ninit)
   229  	t := sw.Type
   230  	if t == nil {
   231  		return
   232  	}
   233  
   234  	// convert the switch into OIF statements
   235  	var cas *NodeList
   236  	if s.kind == switchKindTrue || s.kind == switchKindFalse {
   237  		s.exprname = Nodbool(s.kind == switchKindTrue)
   238  	} else if consttype(sw.Ntest) >= 0 {
   239  		// leave constants to enable dead code elimination (issue 9608)
   240  		s.exprname = sw.Ntest
   241  	} else {
   242  		s.exprname = temp(sw.Ntest.Type)
   243  		cas = list1(Nod(OAS, s.exprname, sw.Ntest))
   244  		typechecklist(cas, Etop)
   245  	}
   246  
   247  	// enumerate the cases, and lop off the default case
   248  	cc := caseClauses(sw, s.kind)
   249  	var def *Node
   250  	if len(cc) > 0 && cc[0].typ == caseKindDefault {
   251  		def = cc[0].node.Right
   252  		cc = cc[1:]
   253  	} else {
   254  		def = Nod(OBREAK, nil, nil)
   255  	}
   256  
   257  	// handle the cases in order
   258  	for len(cc) > 0 {
   259  		// deal with expressions one at a time
   260  		if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
   261  			a := s.walkCases(cc[:1])
   262  			cas = list(cas, a)
   263  			cc = cc[1:]
   264  			continue
   265  		}
   266  
   267  		// do binary search on runs of constants
   268  		var run int
   269  		for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
   270  		}
   271  
   272  		// sort and compile constants
   273  		sort.Sort(caseClauseByExpr(cc[:run]))
   274  		a := s.walkCases(cc[:run])
   275  		cas = list(cas, a)
   276  		cc = cc[run:]
   277  	}
   278  
   279  	// handle default case
   280  	if nerrors == 0 {
   281  		cas = list(cas, def)
   282  		sw.Nbody = concat(cas, sw.Nbody)
   283  		sw.List = nil
   284  		walkstmtlist(sw.Nbody)
   285  	}
   286  }
   287  
   288  // walkCases generates an AST implementing the cases in cc.
   289  func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
   290  	if len(cc) < binarySearchMin {
   291  		// linear search
   292  		var cas *NodeList
   293  		for _, c := range cc {
   294  			n := c.node
   295  			lno := int(setlineno(n))
   296  
   297  			a := Nod(OIF, nil, nil)
   298  			if (s.kind != switchKindTrue && s.kind != switchKindFalse) || assignop(n.Left.Type, s.exprname.Type, nil) == OCONVIFACE || assignop(s.exprname.Type, n.Left.Type, nil) == OCONVIFACE {
   299  				a.Ntest = Nod(OEQ, s.exprname, n.Left) // if name == val
   300  				typecheck(&a.Ntest, Erv)
   301  			} else if s.kind == switchKindTrue {
   302  				a.Ntest = n.Left // if val
   303  			} else {
   304  				// s.kind == switchKindFalse
   305  				a.Ntest = Nod(ONOT, n.Left, nil) // if !val
   306  				typecheck(&a.Ntest, Erv)
   307  			}
   308  			a.Nbody = list1(n.Right) // goto l
   309  
   310  			cas = list(cas, a)
   311  			lineno = int32(lno)
   312  		}
   313  		return liststmt(cas)
   314  	}
   315  
   316  	// find the middle and recur
   317  	half := len(cc) / 2
   318  	a := Nod(OIF, nil, nil)
   319  	mid := cc[half-1].node.Left
   320  	le := Nod(OLE, s.exprname, mid)
   321  	if Isconst(mid, CTSTR) {
   322  		// Search by length and then by value; see exprcmp.
   323  		lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
   324  		leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
   325  		a.Ntest = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
   326  	} else {
   327  		a.Ntest = le
   328  	}
   329  	typecheck(&a.Ntest, Erv)
   330  	a.Nbody = list1(s.walkCases(cc[:half]))
   331  	a.Nelse = list1(s.walkCases(cc[half:]))
   332  	return a
   333  }
   334  
   335  // casebody builds separate lists of statements and cases.
   336  // It makes labels between cases and statements
   337  // and deals with fallthrough, break, and unreachable statements.
   338  func casebody(sw *Node, typeswvar *Node) {
   339  	if sw.List == nil {
   340  		return
   341  	}
   342  
   343  	lno := setlineno(sw)
   344  
   345  	var cas *NodeList  // cases
   346  	var stat *NodeList // statements
   347  	var def *Node      // defaults
   348  	br := Nod(OBREAK, nil, nil)
   349  
   350  	for l := sw.List; l != nil; l = l.Next {
   351  		n := l.N
   352  		setlineno(n)
   353  		if n.Op != OXCASE {
   354  			Fatal("casebody %v", Oconv(int(n.Op), 0))
   355  		}
   356  		n.Op = OCASE
   357  		needvar := count(n.List) != 1 || n.List.N.Op == OLITERAL
   358  
   359  		jmp := Nod(OGOTO, newCaseLabel(), nil)
   360  		if n.List == nil {
   361  			if def != nil {
   362  				Yyerror("more than one default case")
   363  			}
   364  			// reuse original default case
   365  			n.Right = jmp
   366  			def = n
   367  		}
   368  
   369  		if n.List != nil && n.List.Next == nil {
   370  			// one case -- reuse OCASE node
   371  			n.Left = n.List.N
   372  			n.Right = jmp
   373  			n.List = nil
   374  			cas = list(cas, n)
   375  		} else {
   376  			// expand multi-valued cases
   377  			for lc := n.List; lc != nil; lc = lc.Next {
   378  				cas = list(cas, Nod(OCASE, lc.N, jmp))
   379  			}
   380  		}
   381  
   382  		stat = list(stat, Nod(OLABEL, jmp.Left, nil))
   383  		if typeswvar != nil && needvar && n.Nname != nil {
   384  			l := list1(Nod(ODCL, n.Nname, nil))
   385  			l = list(l, Nod(OAS, n.Nname, typeswvar))
   386  			typechecklist(l, Etop)
   387  			stat = concat(stat, l)
   388  		}
   389  		stat = concat(stat, n.Nbody)
   390  
   391  		// botch - shouldn't fall thru declaration
   392  		last := stat.End.N
   393  		if last.Xoffset == n.Xoffset && last.Op == OXFALL {
   394  			if typeswvar != nil {
   395  				setlineno(last)
   396  				Yyerror("cannot fallthrough in type switch")
   397  			}
   398  
   399  			if l.Next == nil {
   400  				setlineno(last)
   401  				Yyerror("cannot fallthrough final case in switch")
   402  			}
   403  
   404  			last.Op = OFALL
   405  		} else {
   406  			stat = list(stat, br)
   407  		}
   408  	}
   409  
   410  	stat = list(stat, br)
   411  	if def != nil {
   412  		cas = list(cas, def)
   413  	}
   414  
   415  	sw.List = cas
   416  	sw.Nbody = stat
   417  	lineno = lno
   418  }
   419  
   420  // nSwitchLabel is the number of switch labels generated.
   421  // This should be per-function, but it is a global counter for now.
   422  var nSwitchLabel int
   423  
   424  func newCaseLabel() *Node {
   425  	label := strconv.Itoa(nSwitchLabel)
   426  	nSwitchLabel++
   427  	return newname(Lookup(label))
   428  }
   429  
   430  // caseClauses generates a slice of caseClauses
   431  // corresponding to the clauses in the switch statement sw.
   432  // Kind is the kind of switch statement.
   433  func caseClauses(sw *Node, kind int) []*caseClause {
   434  	var cc []*caseClause
   435  	for l := sw.List; l != nil; l = l.Next {
   436  		n := l.N
   437  		c := new(caseClause)
   438  		cc = append(cc, c)
   439  		c.ordinal = len(cc)
   440  		c.node = n
   441  
   442  		if n.Left == nil {
   443  			c.typ = caseKindDefault
   444  			continue
   445  		}
   446  
   447  		if kind == switchKindType {
   448  			// type switch
   449  			switch {
   450  			case n.Left.Op == OLITERAL:
   451  				c.typ = caseKindTypeNil
   452  			case Istype(n.Left.Type, TINTER):
   453  				c.typ = caseKindTypeVar
   454  			default:
   455  				c.typ = caseKindTypeConst
   456  				c.hash = typehash(n.Left.Type)
   457  			}
   458  		} else {
   459  			// expression switch
   460  			switch consttype(n.Left) {
   461  			case CTFLT, CTINT, CTRUNE, CTSTR:
   462  				c.typ = caseKindExprConst
   463  			default:
   464  				c.typ = caseKindExprVar
   465  			}
   466  		}
   467  	}
   468  
   469  	if cc == nil {
   470  		return nil
   471  	}
   472  
   473  	// sort by value and diagnose duplicate cases
   474  	if kind == switchKindType {
   475  		// type switch
   476  		sort.Sort(caseClauseByType(cc))
   477  		for i, c1 := range cc {
   478  			if c1.typ == caseKindTypeNil || c1.typ == caseKindDefault {
   479  				break
   480  			}
   481  			for _, c2 := range cc[i+1:] {
   482  				if c2.typ == caseKindTypeNil || c2.typ == caseKindDefault || c1.hash != c2.hash {
   483  					break
   484  				}
   485  				if Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
   486  					yyerrorl(int(c2.node.Lineno), "duplicate case %v in type switch\n\tprevious case at %v", c2.node.Left.Type, c1.node.Line())
   487  				}
   488  			}
   489  		}
   490  	} else {
   491  		// expression switch
   492  		sort.Sort(caseClauseByExpr(cc))
   493  		for i, c1 := range cc {
   494  			if i+1 == len(cc) {
   495  				break
   496  			}
   497  			c2 := cc[i+1]
   498  			if exprcmp(c1, c2) != 0 {
   499  				continue
   500  			}
   501  			setlineno(c2.node)
   502  			Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line())
   503  		}
   504  	}
   505  
   506  	// put list back in processing order
   507  	sort.Sort(caseClauseByOrd(cc))
   508  	return cc
   509  }
   510  
   511  // walk generates an AST that implements sw,
   512  // where sw is a type switch.
   513  // The AST is generally of the form of a linear
   514  // search using if..goto, although binary search
   515  // is used with long runs of concrete types.
   516  func (s *typeSwitch) walk(sw *Node) {
   517  	if sw.Ntest == nil {
   518  		return
   519  	}
   520  	if sw.Ntest.Right == nil {
   521  		setlineno(sw)
   522  		Yyerror("type switch must have an assignment")
   523  		return
   524  	}
   525  
   526  	walkexpr(&sw.Ntest.Right, &sw.Ninit)
   527  	if !Istype(sw.Ntest.Right.Type, TINTER) {
   528  		Yyerror("type switch must be on an interface")
   529  		return
   530  	}
   531  
   532  	var cas *NodeList
   533  
   534  	// predeclare temporary variables and the boolean var
   535  	s.facename = temp(sw.Ntest.Right.Type)
   536  
   537  	a := Nod(OAS, s.facename, sw.Ntest.Right)
   538  	typecheck(&a, Etop)
   539  	cas = list(cas, a)
   540  
   541  	s.okname = temp(Types[TBOOL])
   542  	typecheck(&s.okname, Erv)
   543  
   544  	s.hashname = temp(Types[TUINT32])
   545  	typecheck(&s.hashname, Erv)
   546  
   547  	// set up labels and jumps
   548  	casebody(sw, s.facename)
   549  
   550  	// calculate type hash
   551  	t := sw.Ntest.Right.Type
   552  	if isnilinter(t) {
   553  		a = syslook("efacethash", 1)
   554  	} else {
   555  		a = syslook("ifacethash", 1)
   556  	}
   557  	substArgTypes(a, t)
   558  	a = Nod(OCALL, a, nil)
   559  	a.List = list1(s.facename)
   560  	a = Nod(OAS, s.hashname, a)
   561  	typecheck(&a, Etop)
   562  	cas = list(cas, a)
   563  
   564  	cc := caseClauses(sw, switchKindType)
   565  	var def *Node
   566  	if len(cc) > 0 && cc[0].typ == caseKindDefault {
   567  		def = cc[0].node.Right
   568  		cc = cc[1:]
   569  	} else {
   570  		def = Nod(OBREAK, nil, nil)
   571  	}
   572  
   573  	// insert type equality check into each case block
   574  	for _, c := range cc {
   575  		n := c.node
   576  		switch c.typ {
   577  		case caseKindTypeNil:
   578  			var v Val
   579  			v.Ctype = CTNIL
   580  			a = Nod(OIF, nil, nil)
   581  			a.Ntest = Nod(OEQ, s.facename, nodlit(v))
   582  			typecheck(&a.Ntest, Erv)
   583  			a.Nbody = list1(n.Right) // if i==nil { goto l }
   584  			n.Right = a
   585  
   586  		case caseKindTypeVar, caseKindTypeConst:
   587  			n.Right = s.typeone(n)
   588  		}
   589  	}
   590  
   591  	// generate list of if statements, binary search for constant sequences
   592  	for len(cc) > 0 {
   593  		if cc[0].typ != caseKindTypeConst {
   594  			n := cc[0].node
   595  			cas = list(cas, n.Right)
   596  			cc = cc[1:]
   597  			continue
   598  		}
   599  
   600  		// identify run of constants
   601  		var run int
   602  		for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
   603  		}
   604  
   605  		// sort by hash
   606  		sort.Sort(caseClauseByType(cc[:run]))
   607  
   608  		// for debugging: linear search
   609  		if false {
   610  			for i := 0; i < run; i++ {
   611  				n := cc[i].node
   612  				cas = list(cas, n.Right)
   613  			}
   614  			continue
   615  		}
   616  
   617  		// combine adjacent cases with the same hash
   618  		ncase := 0
   619  		for i := 0; i < run; i++ {
   620  			ncase++
   621  			hash := list1(cc[i].node.Right)
   622  			for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
   623  				hash = list(hash, cc[j].node.Right)
   624  			}
   625  			cc[i].node.Right = liststmt(hash)
   626  		}
   627  
   628  		// binary search among cases to narrow by hash
   629  		cas = list(cas, s.walkCases(cc[:ncase]))
   630  		cc = cc[ncase:]
   631  	}
   632  
   633  	// handle default case
   634  	if nerrors == 0 {
   635  		cas = list(cas, def)
   636  		sw.Nbody = concat(cas, sw.Nbody)
   637  		sw.List = nil
   638  		walkstmtlist(sw.Nbody)
   639  	}
   640  }
   641  
   642  // typeone generates an AST that jumps to the
   643  // case body if the variable is of type t.
   644  func (s *typeSwitch) typeone(t *Node) *Node {
   645  	name := t.Nname
   646  	var init *NodeList
   647  	if name == nil {
   648  		typecheck(&nblank, Erv|Easgn)
   649  		name = nblank
   650  	} else {
   651  		init = list1(Nod(ODCL, name, nil))
   652  	}
   653  
   654  	a := Nod(OAS2, nil, nil)
   655  	a.List = list(list1(name), s.okname) // name, ok =
   656  	b := Nod(ODOTTYPE, s.facename, nil)
   657  	b.Type = t.Left.Type // interface.(type)
   658  	a.Rlist = list1(b)
   659  	typecheck(&a, Etop)
   660  	init = list(init, a)
   661  
   662  	c := Nod(OIF, nil, nil)
   663  	c.Ntest = s.okname
   664  	c.Nbody = list1(t.Right) // if ok { goto l }
   665  
   666  	return liststmt(list(init, c))
   667  }
   668  
   669  // walkCases generates an AST implementing the cases in cc.
   670  func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
   671  	if len(cc) < binarySearchMin {
   672  		var cas *NodeList
   673  		for _, c := range cc {
   674  			n := c.node
   675  			if c.typ != caseKindTypeConst {
   676  				Fatal("typeSwitch walkCases")
   677  			}
   678  			a := Nod(OIF, nil, nil)
   679  			a.Ntest = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
   680  			typecheck(&a.Ntest, Erv)
   681  			a.Nbody = list1(n.Right)
   682  			cas = list(cas, a)
   683  		}
   684  		return liststmt(cas)
   685  	}
   686  
   687  	// find the middle and recur
   688  	half := len(cc) / 2
   689  	a := Nod(OIF, nil, nil)
   690  	a.Ntest = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
   691  	typecheck(&a.Ntest, Erv)
   692  	a.Nbody = list1(s.walkCases(cc[:half]))
   693  	a.Nelse = list1(s.walkCases(cc[half:]))
   694  	return a
   695  }
   696  
   697  type caseClauseByOrd []*caseClause
   698  
   699  func (x caseClauseByOrd) Len() int      { return len(x) }
   700  func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   701  func (x caseClauseByOrd) Less(i, j int) bool {
   702  	c1, c2 := x[i], x[j]
   703  	switch {
   704  	// sort default first
   705  	case c1.typ == caseKindDefault:
   706  		return true
   707  	case c2.typ == caseKindDefault:
   708  		return false
   709  
   710  	// sort nil second
   711  	case c1.typ == caseKindTypeNil:
   712  		return true
   713  	case c2.typ == caseKindTypeNil:
   714  		return false
   715  	}
   716  
   717  	// sort by ordinal
   718  	return c1.ordinal < c2.ordinal
   719  }
   720  
   721  type caseClauseByExpr []*caseClause
   722  
   723  func (x caseClauseByExpr) Len() int      { return len(x) }
   724  func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   725  func (x caseClauseByExpr) Less(i, j int) bool {
   726  	return exprcmp(x[i], x[j]) < 0
   727  }
   728  
   729  func exprcmp(c1, c2 *caseClause) int {
   730  	// sort non-constants last
   731  	if c1.typ != caseKindExprConst {
   732  		return +1
   733  	}
   734  	if c2.typ != caseKindExprConst {
   735  		return -1
   736  	}
   737  
   738  	n1 := c1.node.Left
   739  	n2 := c2.node.Left
   740  
   741  	// sort by type (for switches on interface)
   742  	ct := int(n1.Val.Ctype)
   743  	if ct > int(n2.Val.Ctype) {
   744  		return +1
   745  	}
   746  	if ct < int(n2.Val.Ctype) {
   747  		return -1
   748  	}
   749  	if !Eqtype(n1.Type, n2.Type) {
   750  		if n1.Type.Vargen > n2.Type.Vargen {
   751  			return +1
   752  		} else {
   753  			return -1
   754  		}
   755  	}
   756  
   757  	// sort by constant value to enable binary search
   758  	switch ct {
   759  	case CTFLT:
   760  		return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval)
   761  	case CTINT, CTRUNE:
   762  		return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval)
   763  	case CTSTR:
   764  		// Sort strings by length and then by value.
   765  		// It is much cheaper to compare lengths than values,
   766  		// and all we need here is consistency.
   767  		// We respect this sorting in exprSwitch.walkCases.
   768  		a := n1.Val.U.Sval
   769  		b := n2.Val.U.Sval
   770  		if len(a) < len(b) {
   771  			return -1
   772  		}
   773  		if len(a) > len(b) {
   774  			return +1
   775  		}
   776  		return stringsCompare(a, b)
   777  	}
   778  
   779  	return 0
   780  }
   781  
   782  type caseClauseByType []*caseClause
   783  
   784  func (x caseClauseByType) Len() int      { return len(x) }
   785  func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   786  func (x caseClauseByType) Less(i, j int) bool {
   787  	c1, c2 := x[i], x[j]
   788  	switch {
   789  	// sort non-constants last
   790  	case c1.typ != caseKindTypeConst:
   791  		return false
   792  	case c2.typ != caseKindTypeConst:
   793  		return true
   794  
   795  	// sort by hash code
   796  	case c1.hash != c2.hash:
   797  		return c1.hash < c2.hash
   798  	}
   799  
   800  	// sort by ordinal
   801  	return c1.ordinal < c2.ordinal
   802  }
   803  
   804  func dumpcase(cc []*caseClause) {
   805  	for _, c := range cc {
   806  		switch c.typ {
   807  		case caseKindDefault:
   808  			fmt.Printf("case-default\n")
   809  			fmt.Printf("\tord=%d\n", c.ordinal)
   810  
   811  		case caseKindExprConst:
   812  			fmt.Printf("case-exprconst\n")
   813  			fmt.Printf("\tord=%d\n", c.ordinal)
   814  
   815  		case caseKindExprVar:
   816  			fmt.Printf("case-exprvar\n")
   817  			fmt.Printf("\tord=%d\n", c.ordinal)
   818  			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
   819  
   820  		case caseKindTypeNil:
   821  			fmt.Printf("case-typenil\n")
   822  			fmt.Printf("\tord=%d\n", c.ordinal)
   823  
   824  		case caseKindTypeConst:
   825  			fmt.Printf("case-typeconst\n")
   826  			fmt.Printf("\tord=%d\n", c.ordinal)
   827  			fmt.Printf("\thash=%x\n", c.hash)
   828  
   829  		case caseKindTypeVar:
   830  			fmt.Printf("case-typevar\n")
   831  			fmt.Printf("\tord=%d\n", c.ordinal)
   832  
   833  		default:
   834  			fmt.Printf("case-???\n")
   835  			fmt.Printf("\tord=%d\n", c.ordinal)
   836  			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
   837  			fmt.Printf("\thash=%x\n", c.hash)
   838  		}
   839  	}
   840  
   841  	fmt.Printf("\n")
   842  }