github.com/rsc/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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.Ntest != nil && n.Ntest.Op == OTYPESW {
    70  		// type switch
    71  		top = Etype
    72  		typecheck(&n.Ntest.Right, Erv)
    73  		t = n.Ntest.Right.Type
    74  		if t != nil && t.Etype != TINTER {
    75  			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Ntest.Right, obj.FmtLong))
    76  		}
    77  	} else {
    78  		// expression switch
    79  		top = Erv
    80  		if n.Ntest != nil {
    81  			typecheck(&n.Ntest, Erv)
    82  			defaultlit(&n.Ntest, nil)
    83  			t = n.Ntest.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.Ntest, 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.Ntest, 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.Ntest, obj.FmtLong), Tconv(badtype, 0))
    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", Tconv(ll.N.Type, 0))
   135  					case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0:
   136  						if n.Ntest != nil {
   137  							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", Nconv(ll.N, 0), Nconv(n.Ntest, 0), Tconv(ll.N.Type, 0), Tconv(t, 0))
   138  						} else {
   139  							Yyerror("invalid case %v in switch (mismatched types %v and bool)", Nconv(ll.N, 0), Tconv(ll.N.Type, 0))
   140  						}
   141  					case nilonly != "" && !Isconst(ll.N, CTNIL):
   142  						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", Nconv(ll.N, 0), nilonly, Nconv(n.Ntest, 0))
   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.Ntest.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.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0), Sconv(have.Sym, 0), Tconv(have.Type, obj.FmtShort), Sconv(missing.Sym, 0), 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.Ntest.Right, obj.FmtLong), Tconv(ll.N.Type, 0), Sconv(missing.Sym, 0))
   160  						}
   161  					}
   162  				}
   163  			}
   164  		}
   165  
   166  		if top == Etype && n.Type != nil {
   167  			ll = ncase.List
   168  			nvar := ncase.Nname
   169  			if nvar != nil {
   170  				if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
   171  					// single entry type switch
   172  					nvar.Ntype = typenod(ll.N.Type)
   173  				} else {
   174  					// multiple entry type switch or default
   175  					nvar.Ntype = typenod(n.Type)
   176  				}
   177  
   178  				typecheck(&nvar, Erv|Easgn)
   179  				ncase.Nname = 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.Ntest == nil {
   193  		sw.Ntest = Nodbool(true)
   194  		typecheck(&sw.Ntest, Erv)
   195  	}
   196  
   197  	if sw.Ntest.Op == OTYPESW {
   198  		var s typeSwitch
   199  		s.walk(sw)
   200  	} else {
   201  		var s exprSwitch
   202  		s.walk(sw)
   203  	}
   204  
   205  	// Discard old AST elements. They can confuse racewalk.
   206  	sw.Ntest = nil
   207  	sw.List = nil
   208  }
   209  
   210  // walk generates an AST implementing sw.
   211  // sw is an expression switch.
   212  // The AST is generally of the form of a linear
   213  // search using if..goto, although binary search
   214  // is used with long runs of constants.
   215  func (s *exprSwitch) walk(sw *Node) {
   216  	casebody(sw, nil)
   217  
   218  	s.kind = switchKindExpr
   219  	if Isconst(sw.Ntest, CTBOOL) {
   220  		s.kind = switchKindTrue
   221  		if !sw.Ntest.Val.U.Bval {
   222  			s.kind = switchKindFalse
   223  		}
   224  	}
   225  
   226  	walkexpr(&sw.Ntest, &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(sw.Ntest) >= 0 {
   237  		// leave constants to enable dead code elimination (issue 9608)
   238  		s.exprname = sw.Ntest
   239  	} else {
   240  		s.exprname = temp(sw.Ntest.Type)
   241  		cas = list1(Nod(OAS, s.exprname, sw.Ntest))
   242  		typechecklist(cas, Etop)
   243  	}
   244  
   245  	// enumerate the cases, and lop off the default case
   246  	cc := caseClauses(sw, s.kind)
   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  		sw.List = nil
   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.Ntest = Nod(OEQ, s.exprname, n.Left) // if name == val
   298  				typecheck(&a.Ntest, Erv)
   299  			} else if s.kind == switchKindTrue {
   300  				a.Ntest = n.Left // if val
   301  			} else {
   302  				// s.kind == switchKindFalse
   303  				a.Ntest = Nod(ONOT, n.Left, nil) // if !val
   304  				typecheck(&a.Ntest, 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.Ntest = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
   324  	} else {
   325  		a.Ntest = le
   326  	}
   327  	typecheck(&a.Ntest, Erv)
   328  	a.Nbody = list1(s.walkCases(cc[:half]))
   329  	a.Nelse = 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  			Fatal("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.Nname != nil {
   382  			l := list1(Nod(ODCL, n.Nname, nil))
   383  			l = list(l, Nod(OAS, n.Nname, 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", Tconv(c2.node.Left.Type, 0), 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", Nconv(c1.node.Left, 0), 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  	if sw.Ntest == nil {
   516  		return
   517  	}
   518  	if sw.Ntest.Right == nil {
   519  		setlineno(sw)
   520  		Yyerror("type switch must have an assignment")
   521  		return
   522  	}
   523  
   524  	walkexpr(&sw.Ntest.Right, &sw.Ninit)
   525  	if !Istype(sw.Ntest.Right.Type, TINTER) {
   526  		Yyerror("type switch must be on an interface")
   527  		return
   528  	}
   529  
   530  	var cas *NodeList
   531  
   532  	// predeclare temporary variables and the boolean var
   533  	s.facename = temp(sw.Ntest.Right.Type)
   534  
   535  	a := Nod(OAS, s.facename, sw.Ntest.Right)
   536  	typecheck(&a, Etop)
   537  	cas = list(cas, a)
   538  
   539  	s.okname = temp(Types[TBOOL])
   540  	typecheck(&s.okname, Erv)
   541  
   542  	s.hashname = temp(Types[TUINT32])
   543  	typecheck(&s.hashname, Erv)
   544  
   545  	// set up labels and jumps
   546  	casebody(sw, s.facename)
   547  
   548  	// calculate type hash
   549  	t := sw.Ntest.Right.Type
   550  	if isnilinter(t) {
   551  		a = syslook("efacethash", 1)
   552  	} else {
   553  		a = syslook("ifacethash", 1)
   554  	}
   555  	substArgTypes(a, t)
   556  	a = Nod(OCALL, a, nil)
   557  	a.List = list1(s.facename)
   558  	a = Nod(OAS, s.hashname, a)
   559  	typecheck(&a, Etop)
   560  	cas = list(cas, a)
   561  
   562  	cc := caseClauses(sw, switchKindType)
   563  	var def *Node
   564  	if len(cc) > 0 && cc[0].typ == caseKindDefault {
   565  		def = cc[0].node.Right
   566  		cc = cc[1:]
   567  	} else {
   568  		def = Nod(OBREAK, nil, nil)
   569  	}
   570  
   571  	// insert type equality check into each case block
   572  	for _, c := range cc {
   573  		n := c.node
   574  		switch c.typ {
   575  		case caseKindTypeNil:
   576  			var v Val
   577  			v.Ctype = CTNIL
   578  			a = Nod(OIF, nil, nil)
   579  			a.Ntest = Nod(OEQ, s.facename, nodlit(v))
   580  			typecheck(&a.Ntest, Erv)
   581  			a.Nbody = list1(n.Right) // if i==nil { goto l }
   582  			n.Right = a
   583  
   584  		case caseKindTypeVar, caseKindTypeConst:
   585  			n.Right = s.typeone(n)
   586  		}
   587  	}
   588  
   589  	// generate list of if statements, binary search for constant sequences
   590  	for len(cc) > 0 {
   591  		if cc[0].typ != caseKindTypeConst {
   592  			n := cc[0].node
   593  			cas = list(cas, n.Right)
   594  			cc = cc[1:]
   595  			continue
   596  		}
   597  
   598  		// identify run of constants
   599  		var run int
   600  		for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
   601  		}
   602  
   603  		// sort by hash
   604  		sort.Sort(caseClauseByType(cc[:run]))
   605  
   606  		// for debugging: linear search
   607  		if false {
   608  			for i := 0; i < run; i++ {
   609  				n := cc[i].node
   610  				cas = list(cas, n.Right)
   611  			}
   612  			continue
   613  		}
   614  
   615  		// combine adjacent cases with the same hash
   616  		ncase := 0
   617  		for i := 0; i < run; i++ {
   618  			ncase++
   619  			hash := list1(cc[i].node.Right)
   620  			for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
   621  				hash = list(hash, cc[j].node.Right)
   622  			}
   623  			cc[i].node.Right = liststmt(hash)
   624  		}
   625  
   626  		// binary search among cases to narrow by hash
   627  		cas = list(cas, s.walkCases(cc[:ncase]))
   628  		cc = cc[ncase:]
   629  	}
   630  
   631  	// handle default case
   632  	if nerrors == 0 {
   633  		cas = list(cas, def)
   634  		sw.Nbody = concat(cas, sw.Nbody)
   635  		sw.List = nil
   636  		walkstmtlist(sw.Nbody)
   637  	}
   638  }
   639  
   640  // typeone generates an AST that jumps to the
   641  // case body if the variable is of type t.
   642  func (s *typeSwitch) typeone(t *Node) *Node {
   643  	name := t.Nname
   644  	var init *NodeList
   645  	if name == nil {
   646  		typecheck(&nblank, Erv|Easgn)
   647  		name = nblank
   648  	} else {
   649  		init = list1(Nod(ODCL, name, nil))
   650  	}
   651  
   652  	a := Nod(OAS2, nil, nil)
   653  	a.List = list(list1(name), s.okname) // name, ok =
   654  	b := Nod(ODOTTYPE, s.facename, nil)
   655  	b.Type = t.Left.Type // interface.(type)
   656  	a.Rlist = list1(b)
   657  	typecheck(&a, Etop)
   658  	init = list(init, a)
   659  
   660  	c := Nod(OIF, nil, nil)
   661  	c.Ntest = s.okname
   662  	c.Nbody = list1(t.Right) // if ok { goto l }
   663  
   664  	return liststmt(list(init, c))
   665  }
   666  
   667  // walkCases generates an AST implementing the cases in cc.
   668  func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
   669  	if len(cc) < binarySearchMin {
   670  		var cas *NodeList
   671  		for _, c := range cc {
   672  			n := c.node
   673  			if c.typ != caseKindTypeConst {
   674  				Fatal("typeSwitch walkCases")
   675  			}
   676  			a := Nod(OIF, nil, nil)
   677  			a.Ntest = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
   678  			typecheck(&a.Ntest, Erv)
   679  			a.Nbody = list1(n.Right)
   680  			cas = list(cas, a)
   681  		}
   682  		return liststmt(cas)
   683  	}
   684  
   685  	// find the middle and recur
   686  	half := len(cc) / 2
   687  	a := Nod(OIF, nil, nil)
   688  	a.Ntest = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
   689  	typecheck(&a.Ntest, Erv)
   690  	a.Nbody = list1(s.walkCases(cc[:half]))
   691  	a.Nelse = list1(s.walkCases(cc[half:]))
   692  	return a
   693  }
   694  
   695  type caseClauseByOrd []*caseClause
   696  
   697  func (x caseClauseByOrd) Len() int      { return len(x) }
   698  func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   699  func (x caseClauseByOrd) Less(i, j int) bool {
   700  	c1, c2 := x[i], x[j]
   701  	switch {
   702  	// sort default first
   703  	case c1.typ == caseKindDefault:
   704  		return true
   705  	case c2.typ == caseKindDefault:
   706  		return false
   707  
   708  	// sort nil second
   709  	case c1.typ == caseKindTypeNil:
   710  		return true
   711  	case c2.typ == caseKindTypeNil:
   712  		return false
   713  	}
   714  
   715  	// sort by ordinal
   716  	return c1.ordinal < c2.ordinal
   717  }
   718  
   719  type caseClauseByExpr []*caseClause
   720  
   721  func (x caseClauseByExpr) Len() int      { return len(x) }
   722  func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   723  func (x caseClauseByExpr) Less(i, j int) bool {
   724  	return exprcmp(x[i], x[j]) < 0
   725  }
   726  
   727  func exprcmp(c1, c2 *caseClause) int {
   728  	// sort non-constants last
   729  	if c1.typ != caseKindExprConst {
   730  		return +1
   731  	}
   732  	if c2.typ != caseKindExprConst {
   733  		return -1
   734  	}
   735  
   736  	n1 := c1.node.Left
   737  	n2 := c2.node.Left
   738  
   739  	// sort by type (for switches on interface)
   740  	ct := int(n1.Val.Ctype)
   741  	if ct > int(n2.Val.Ctype) {
   742  		return +1
   743  	}
   744  	if ct < int(n2.Val.Ctype) {
   745  		return -1
   746  	}
   747  	if !Eqtype(n1.Type, n2.Type) {
   748  		if n1.Type.Vargen > n2.Type.Vargen {
   749  			return +1
   750  		} else {
   751  			return -1
   752  		}
   753  	}
   754  
   755  	// sort by constant value to enable binary search
   756  	switch ct {
   757  	case CTFLT:
   758  		return mpcmpfltflt(n1.Val.U.Fval, n2.Val.U.Fval)
   759  	case CTINT, CTRUNE:
   760  		return Mpcmpfixfix(n1.Val.U.Xval, n2.Val.U.Xval)
   761  	case CTSTR:
   762  		// Sort strings by length and then by value.
   763  		// It is much cheaper to compare lengths than values,
   764  		// and all we need here is consistency.
   765  		// We respect this sorting in exprSwitch.walkCases.
   766  		a := n1.Val.U.Sval
   767  		b := n2.Val.U.Sval
   768  		if len(a) < len(b) {
   769  			return -1
   770  		}
   771  		if len(a) > len(b) {
   772  			return +1
   773  		}
   774  		return stringsCompare(a, b)
   775  	}
   776  
   777  	return 0
   778  }
   779  
   780  type caseClauseByType []*caseClause
   781  
   782  func (x caseClauseByType) Len() int      { return len(x) }
   783  func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   784  func (x caseClauseByType) Less(i, j int) bool {
   785  	c1, c2 := x[i], x[j]
   786  	switch {
   787  	// sort non-constants last
   788  	case c1.typ != caseKindTypeConst:
   789  		return false
   790  	case c2.typ != caseKindTypeConst:
   791  		return true
   792  
   793  	// sort by hash code
   794  	case c1.hash != c2.hash:
   795  		return c1.hash < c2.hash
   796  	}
   797  
   798  	// sort by ordinal
   799  	return c1.ordinal < c2.ordinal
   800  }
   801  
   802  func dumpcase(cc []*caseClause) {
   803  	for _, c := range cc {
   804  		switch c.typ {
   805  		case caseKindDefault:
   806  			fmt.Printf("case-default\n")
   807  			fmt.Printf("\tord=%d\n", c.ordinal)
   808  
   809  		case caseKindExprConst:
   810  			fmt.Printf("case-exprconst\n")
   811  			fmt.Printf("\tord=%d\n", c.ordinal)
   812  
   813  		case caseKindExprVar:
   814  			fmt.Printf("case-exprvar\n")
   815  			fmt.Printf("\tord=%d\n", c.ordinal)
   816  			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
   817  
   818  		case caseKindTypeNil:
   819  			fmt.Printf("case-typenil\n")
   820  			fmt.Printf("\tord=%d\n", c.ordinal)
   821  
   822  		case caseKindTypeConst:
   823  			fmt.Printf("case-typeconst\n")
   824  			fmt.Printf("\tord=%d\n", c.ordinal)
   825  			fmt.Printf("\thash=%x\n", c.hash)
   826  
   827  		case caseKindTypeVar:
   828  			fmt.Printf("case-typevar\n")
   829  			fmt.Printf("\tord=%d\n", c.ordinal)
   830  
   831  		default:
   832  			fmt.Printf("case-???\n")
   833  			fmt.Printf("\tord=%d\n", c.ordinal)
   834  			fmt.Printf("\top=%v\n", Oconv(int(c.node.Left.Op), 0))
   835  			fmt.Printf("\thash=%x\n", c.hash)
   836  		}
   837  	}
   838  
   839  	fmt.Printf("\n")
   840  }