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