github.com/gocuntian/go@v0.0.0-20160610041250-fee02d270bf8/src/cmd/compile/internal/gc/swt.go (about)

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