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