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