github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 *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 n1.Op != OTYPE && n1.Type != nil: // should this be ||?
   154  						Yyerror("%v is not a type", Nconv(n1, FmtLong))
   155  						// reset to original type
   156  						n1 = n.Left.Right
   157  						ls[i1] = n1
   158  					case !n1.Type.IsInterface() && t.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr):
   159  						if have != nil && !missing.Broke && !have.Broke {
   160  							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))
   161  						} else if !missing.Broke {
   162  							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym)
   163  						}
   164  					}
   165  				}
   166  			}
   167  		}
   168  
   169  		if top == Etype && n.Type != nil {
   170  			ll := ncase.List
   171  			if ncase.Rlist.Len() != 0 {
   172  				nvar := ncase.Rlist.First()
   173  				if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) {
   174  					// single entry type switch
   175  					nvar.Name.Param.Ntype = typenod(ll.First().Type)
   176  				} else {
   177  					// multiple entry type switch or default
   178  					nvar.Name.Param.Ntype = typenod(n.Type)
   179  				}
   180  
   181  				nvar = typecheck(nvar, Erv|Easgn)
   182  				ncase.Rlist.SetIndex(0, nvar)
   183  			}
   184  		}
   185  
   186  		typecheckslice(ncase.Nbody.Slice(), Etop)
   187  	}
   188  
   189  	lineno = lno
   190  }
   191  
   192  // walkswitch walks a switch statement.
   193  func walkswitch(sw *Node) {
   194  	// convert switch {...} to switch true {...}
   195  	if sw.Left == nil {
   196  		sw.Left = Nodbool(true)
   197  		sw.Left = typecheck(sw.Left, Erv)
   198  	}
   199  
   200  	if sw.Left.Op == OTYPESW {
   201  		var s typeSwitch
   202  		s.walk(sw)
   203  	} else {
   204  		var s exprSwitch
   205  		s.walk(sw)
   206  	}
   207  }
   208  
   209  // walk generates an AST implementing sw.
   210  // sw is an expression switch.
   211  // The AST is generally of the form of a linear
   212  // search using if..goto, although binary search
   213  // is used with long runs of constants.
   214  func (s *exprSwitch) walk(sw *Node) {
   215  	casebody(sw, nil)
   216  
   217  	cond := sw.Left
   218  	sw.Left = nil
   219  
   220  	s.kind = switchKindExpr
   221  	if Isconst(cond, CTBOOL) {
   222  		s.kind = switchKindTrue
   223  		if !cond.Val().U.(bool) {
   224  			s.kind = switchKindFalse
   225  		}
   226  	}
   227  
   228  	cond = walkexpr(cond, &sw.Ninit)
   229  	t := sw.Type
   230  	if t == nil {
   231  		return
   232  	}
   233  
   234  	// convert the switch into OIF statements
   235  	var cas []*Node
   236  	if s.kind == switchKindTrue || s.kind == switchKindFalse {
   237  		s.exprname = Nodbool(s.kind == switchKindTrue)
   238  	} else if consttype(cond) >= 0 {
   239  		// leave constants to enable dead code elimination (issue 9608)
   240  		s.exprname = cond
   241  	} else {
   242  		s.exprname = temp(cond.Type)
   243  		cas = []*Node{Nod(OAS, s.exprname, cond)}
   244  		typecheckslice(cas, Etop)
   245  	}
   246  
   247  	// enumerate the cases, and lop off the default case
   248  	cc := caseClauses(sw, s.kind)
   249  	sw.List.Set(nil)
   250  	var def *Node
   251  	if len(cc) > 0 && cc[0].typ == caseKindDefault {
   252  		def = cc[0].node.Right
   253  		cc = cc[1:]
   254  	} else {
   255  		def = Nod(OBREAK, nil, nil)
   256  	}
   257  
   258  	// handle the cases in order
   259  	for len(cc) > 0 {
   260  		// deal with expressions one at a time
   261  		if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
   262  			a := s.walkCases(cc[:1])
   263  			cas = append(cas, a)
   264  			cc = cc[1:]
   265  			continue
   266  		}
   267  
   268  		// do binary search on runs of constants
   269  		var run int
   270  		for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
   271  		}
   272  
   273  		// sort and compile constants
   274  		sort.Sort(caseClauseByExpr(cc[:run]))
   275  		a := s.walkCases(cc[:run])
   276  		cas = append(cas, a)
   277  		cc = cc[run:]
   278  	}
   279  
   280  	// handle default case
   281  	if nerrors == 0 {
   282  		cas = append(cas, def)
   283  		sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
   284  		walkstmtlist(sw.Nbody.Slice())
   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 []*Node
   293  		for _, c := range cc {
   294  			n := c.node
   295  			lno := 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.Left = Nod(OEQ, s.exprname, n.Left) // if name == val
   300  				a.Left = typecheck(a.Left, Erv)
   301  			} else if s.kind == switchKindTrue {
   302  				a.Left = n.Left // if val
   303  			} else {
   304  				// s.kind == switchKindFalse
   305  				a.Left = Nod(ONOT, n.Left, nil) // if !val
   306  				a.Left = typecheck(a.Left, Erv)
   307  			}
   308  			a.Nbody.Set1(n.Right) // goto l
   309  
   310  			cas = append(cas, a)
   311  			lineno = 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.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
   326  	} else {
   327  		a.Left = le
   328  	}
   329  	a.Left = typecheck(a.Left, Erv)
   330  	a.Nbody.Set1(s.walkCases(cc[:half]))
   331  	a.Rlist.Set1(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.Len() == 0 {
   340  		return
   341  	}
   342  
   343  	lno := setlineno(sw)
   344  
   345  	var cas []*Node  // cases
   346  	var stat []*Node // statements
   347  	var def *Node    // defaults
   348  	br := Nod(OBREAK, nil, nil)
   349  
   350  	for i, n := range sw.List.Slice() {
   351  		setlineno(n)
   352  		if n.Op != OXCASE {
   353  			Fatalf("casebody %v", Oconv(n.Op, 0))
   354  		}
   355  		n.Op = OCASE
   356  		needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
   357  
   358  		jmp := Nod(OGOTO, newCaseLabel(), nil)
   359  		if n.List.Len() == 0 {
   360  			if def != nil {
   361  				Yyerror("more than one default case")
   362  			}
   363  			// reuse original default case
   364  			n.Right = jmp
   365  			def = n
   366  		}
   367  
   368  		if n.List.Len() == 1 {
   369  			// one case -- reuse OCASE node
   370  			n.Left = n.List.First()
   371  			n.Right = jmp
   372  			n.List.Set(nil)
   373  			cas = append(cas, n)
   374  		} else {
   375  			// expand multi-valued cases
   376  			for _, n1 := range n.List.Slice() {
   377  				cas = append(cas, Nod(OCASE, n1, jmp))
   378  			}
   379  		}
   380  
   381  		stat = append(stat, Nod(OLABEL, jmp.Left, nil))
   382  		if typeswvar != nil && needvar && n.Rlist.Len() != 0 {
   383  			l := []*Node{
   384  				Nod(ODCL, n.Rlist.First(), nil),
   385  				Nod(OAS, n.Rlist.First(), typeswvar),
   386  			}
   387  			typecheckslice(l, Etop)
   388  			stat = append(stat, l...)
   389  		}
   390  		stat = append(stat, n.Nbody.Slice()...)
   391  
   392  		// botch - shouldn't fall through declaration
   393  		last := stat[len(stat)-1]
   394  		if last.Xoffset == n.Xoffset && last.Op == OXFALL {
   395  			if typeswvar != nil {
   396  				setlineno(last)
   397  				Yyerror("cannot fallthrough in type switch")
   398  			}
   399  
   400  			if i+1 >= sw.List.Len() {
   401  				setlineno(last)
   402  				Yyerror("cannot fallthrough final case in switch")
   403  			}
   404  
   405  			last.Op = OFALL
   406  		} else {
   407  			stat = append(stat, br)
   408  		}
   409  	}
   410  
   411  	stat = append(stat, br)
   412  	if def != nil {
   413  		cas = append(cas, def)
   414  	}
   415  
   416  	sw.List.Set(cas)
   417  	sw.Nbody.Set(stat)
   418  	lineno = lno
   419  }
   420  
   421  // nSwitchLabel is the number of switch labels generated.
   422  // This should be per-function, but it is a global counter for now.
   423  var nSwitchLabel int
   424  
   425  func newCaseLabel() *Node {
   426  	label := strconv.Itoa(nSwitchLabel)
   427  	nSwitchLabel++
   428  	return newname(Lookup(label))
   429  }
   430  
   431  // caseClauses generates a slice of caseClauses
   432  // corresponding to the clauses in the switch statement sw.
   433  // Kind is the kind of switch statement.
   434  func caseClauses(sw *Node, kind int) []*caseClause {
   435  	var cc []*caseClause
   436  	for _, n := range sw.List.Slice() {
   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 n.Left.Type.IsInterface():
   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(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  	cond := sw.Left
   518  	sw.Left = nil
   519  
   520  	if cond == nil {
   521  		sw.List.Set(nil)
   522  		return
   523  	}
   524  	if cond.Right == nil {
   525  		setlineno(sw)
   526  		Yyerror("type switch must have an assignment")
   527  		return
   528  	}
   529  
   530  	cond.Right = walkexpr(cond.Right, &sw.Ninit)
   531  	if !cond.Right.Type.IsInterface() {
   532  		Yyerror("type switch must be on an interface")
   533  		return
   534  	}
   535  
   536  	var cas []*Node
   537  
   538  	// predeclare temporary variables and the boolean var
   539  	s.facename = temp(cond.Right.Type)
   540  
   541  	a := Nod(OAS, s.facename, cond.Right)
   542  	a = typecheck(a, Etop)
   543  	cas = append(cas, a)
   544  
   545  	s.okname = temp(Types[TBOOL])
   546  	s.okname = typecheck(s.okname, Erv)
   547  
   548  	s.hashname = temp(Types[TUINT32])
   549  	s.hashname = typecheck(s.hashname, Erv)
   550  
   551  	// set up labels and jumps
   552  	casebody(sw, s.facename)
   553  
   554  	cc := caseClauses(sw, switchKindType)
   555  	sw.List.Set(nil)
   556  	var def *Node
   557  	if len(cc) > 0 && cc[0].typ == caseKindDefault {
   558  		def = cc[0].node.Right
   559  		cc = cc[1:]
   560  	} else {
   561  		def = Nod(OBREAK, nil, nil)
   562  	}
   563  	var typenil *Node
   564  	if len(cc) > 0 && cc[0].typ == caseKindTypeNil {
   565  		typenil = cc[0].node.Right
   566  		cc = cc[1:]
   567  	}
   568  
   569  	// For empty interfaces, do:
   570  	//     if e._type == nil {
   571  	//         do nil case if it exists, otherwise default
   572  	//     }
   573  	//     h := e._type.hash
   574  	// Use a similar strategy for non-empty interfaces.
   575  
   576  	// Get interface descriptor word.
   577  	typ := Nod(OITAB, s.facename, nil)
   578  
   579  	// Check for nil first.
   580  	i := Nod(OIF, nil, nil)
   581  	i.Left = Nod(OEQ, typ, nodnil())
   582  	if typenil != nil {
   583  		// Do explicit nil case right here.
   584  		i.Nbody.Set1(typenil)
   585  	} else {
   586  		// Jump to default case.
   587  		lbl := newCaseLabel()
   588  		i.Nbody.Set1(Nod(OGOTO, lbl, nil))
   589  		// Wrap default case with label.
   590  		blk := Nod(OBLOCK, nil, nil)
   591  		blk.List.Set([]*Node{Nod(OLABEL, lbl, nil), def})
   592  		def = blk
   593  	}
   594  	i.Left = typecheck(i.Left, Erv)
   595  	cas = append(cas, i)
   596  
   597  	if !cond.Right.Type.IsEmptyInterface() {
   598  		// Load type from itab.
   599  		typ = NodSym(ODOTPTR, typ, nil)
   600  		typ.Type = Ptrto(Types[TUINT8])
   601  		typ.Typecheck = 1
   602  		typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
   603  		typ.Bounded = true            // guaranteed not to fault
   604  	}
   605  	// Load hash from type.
   606  	h := NodSym(ODOTPTR, typ, nil)
   607  	h.Type = Types[TUINT32]
   608  	h.Typecheck = 1
   609  	h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
   610  	h.Bounded = true                // guaranteed not to fault
   611  	a = Nod(OAS, s.hashname, h)
   612  	a = typecheck(a, Etop)
   613  	cas = append(cas, a)
   614  
   615  	// insert type equality check into each case block
   616  	for _, c := range cc {
   617  		n := c.node
   618  		switch c.typ {
   619  		case caseKindTypeVar, caseKindTypeConst:
   620  			n.Right = s.typeone(n)
   621  		default:
   622  			Fatalf("typeSwitch with bad kind: %d", c.typ)
   623  		}
   624  	}
   625  
   626  	// generate list of if statements, binary search for constant sequences
   627  	for len(cc) > 0 {
   628  		if cc[0].typ != caseKindTypeConst {
   629  			n := cc[0].node
   630  			cas = append(cas, n.Right)
   631  			cc = cc[1:]
   632  			continue
   633  		}
   634  
   635  		// identify run of constants
   636  		var run int
   637  		for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
   638  		}
   639  
   640  		// sort by hash
   641  		sort.Sort(caseClauseByType(cc[:run]))
   642  
   643  		// for debugging: linear search
   644  		if false {
   645  			for i := 0; i < run; i++ {
   646  				n := cc[i].node
   647  				cas = append(cas, n.Right)
   648  			}
   649  			continue
   650  		}
   651  
   652  		// combine adjacent cases with the same hash
   653  		ncase := 0
   654  		for i := 0; i < run; i++ {
   655  			ncase++
   656  			hash := []*Node{cc[i].node.Right}
   657  			for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
   658  				hash = append(hash, cc[j].node.Right)
   659  			}
   660  			cc[i].node.Right = liststmt(hash)
   661  		}
   662  
   663  		// binary search among cases to narrow by hash
   664  		cas = append(cas, s.walkCases(cc[:ncase]))
   665  		cc = cc[ncase:]
   666  	}
   667  
   668  	// handle default case
   669  	if nerrors == 0 {
   670  		cas = append(cas, def)
   671  		sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
   672  		sw.List.Set(nil)
   673  		walkstmtlist(sw.Nbody.Slice())
   674  	}
   675  }
   676  
   677  // typeone generates an AST that jumps to the
   678  // case body if the variable is of type t.
   679  func (s *typeSwitch) typeone(t *Node) *Node {
   680  	var name *Node
   681  	var init []*Node
   682  	if t.Rlist.Len() == 0 {
   683  		name = nblank
   684  		nblank = typecheck(nblank, Erv|Easgn)
   685  	} else {
   686  		name = t.Rlist.First()
   687  		init = []*Node{Nod(ODCL, name, nil)}
   688  		a := Nod(OAS, name, nil)
   689  		a = typecheck(a, Etop)
   690  		init = append(init, a)
   691  	}
   692  
   693  	a := Nod(OAS2, nil, nil)
   694  	a.List.Set([]*Node{name, s.okname}) // name, ok =
   695  	b := Nod(ODOTTYPE, s.facename, nil)
   696  	b.Type = t.Left.Type // interface.(type)
   697  	a.Rlist.Set1(b)
   698  	a = typecheck(a, Etop)
   699  	init = append(init, a)
   700  
   701  	c := Nod(OIF, nil, nil)
   702  	c.Left = s.okname
   703  	c.Nbody.Set1(t.Right) // if ok { goto l }
   704  
   705  	return liststmt(append(init, c))
   706  }
   707  
   708  // walkCases generates an AST implementing the cases in cc.
   709  func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
   710  	if len(cc) < binarySearchMin {
   711  		var cas []*Node
   712  		for _, c := range cc {
   713  			n := c.node
   714  			if c.typ != caseKindTypeConst {
   715  				Fatalf("typeSwitch walkCases")
   716  			}
   717  			a := Nod(OIF, nil, nil)
   718  			a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
   719  			a.Left = typecheck(a.Left, Erv)
   720  			a.Nbody.Set1(n.Right)
   721  			cas = append(cas, a)
   722  		}
   723  		return liststmt(cas)
   724  	}
   725  
   726  	// find the middle and recur
   727  	half := len(cc) / 2
   728  	a := Nod(OIF, nil, nil)
   729  	a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
   730  	a.Left = typecheck(a.Left, Erv)
   731  	a.Nbody.Set1(s.walkCases(cc[:half]))
   732  	a.Rlist.Set1(s.walkCases(cc[half:]))
   733  	return a
   734  }
   735  
   736  type caseClauseByOrd []*caseClause
   737  
   738  func (x caseClauseByOrd) Len() int      { return len(x) }
   739  func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   740  func (x caseClauseByOrd) Less(i, j int) bool {
   741  	c1, c2 := x[i], x[j]
   742  	switch {
   743  	// sort default first
   744  	case c1.typ == caseKindDefault:
   745  		return true
   746  	case c2.typ == caseKindDefault:
   747  		return false
   748  
   749  	// sort nil second
   750  	case c1.typ == caseKindTypeNil:
   751  		return true
   752  	case c2.typ == caseKindTypeNil:
   753  		return false
   754  	}
   755  
   756  	// sort by ordinal
   757  	return c1.ordinal < c2.ordinal
   758  }
   759  
   760  type caseClauseByExpr []*caseClause
   761  
   762  func (x caseClauseByExpr) Len() int      { return len(x) }
   763  func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   764  func (x caseClauseByExpr) Less(i, j int) bool {
   765  	return exprcmp(x[i], x[j]) < 0
   766  }
   767  
   768  func exprcmp(c1, c2 *caseClause) int {
   769  	// sort non-constants last
   770  	if c1.typ != caseKindExprConst {
   771  		return +1
   772  	}
   773  	if c2.typ != caseKindExprConst {
   774  		return -1
   775  	}
   776  
   777  	n1 := c1.node.Left
   778  	n2 := c2.node.Left
   779  
   780  	// sort by type (for switches on interface)
   781  	ct := n1.Val().Ctype()
   782  	if ct > n2.Val().Ctype() {
   783  		return +1
   784  	}
   785  	if ct < n2.Val().Ctype() {
   786  		return -1
   787  	}
   788  	if !Eqtype(n1.Type, n2.Type) {
   789  		if n1.Type.Vargen > n2.Type.Vargen {
   790  			return +1
   791  		} else {
   792  			return -1
   793  		}
   794  	}
   795  
   796  	// sort by constant value to enable binary search
   797  	switch ct {
   798  	case CTFLT:
   799  		return n1.Val().U.(*Mpflt).Cmp(n2.Val().U.(*Mpflt))
   800  	case CTINT, CTRUNE:
   801  		return n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint))
   802  	case CTSTR:
   803  		// Sort strings by length and then by value.
   804  		// It is much cheaper to compare lengths than values,
   805  		// and all we need here is consistency.
   806  		// We respect this sorting in exprSwitch.walkCases.
   807  		a := n1.Val().U.(string)
   808  		b := n2.Val().U.(string)
   809  		if len(a) < len(b) {
   810  			return -1
   811  		}
   812  		if len(a) > len(b) {
   813  			return +1
   814  		}
   815  		if a == b {
   816  			return 0
   817  		}
   818  		if a < b {
   819  			return -1
   820  		}
   821  		return +1
   822  	}
   823  
   824  	return 0
   825  }
   826  
   827  type caseClauseByType []*caseClause
   828  
   829  func (x caseClauseByType) Len() int      { return len(x) }
   830  func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   831  func (x caseClauseByType) Less(i, j int) bool {
   832  	c1, c2 := x[i], x[j]
   833  	switch {
   834  	// sort non-constants last
   835  	case c1.typ != caseKindTypeConst:
   836  		return false
   837  	case c2.typ != caseKindTypeConst:
   838  		return true
   839  
   840  	// sort by hash code
   841  	case c1.hash != c2.hash:
   842  		return c1.hash < c2.hash
   843  	}
   844  
   845  	// sort by ordinal
   846  	return c1.ordinal < c2.ordinal
   847  }