github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 "sort"
     8  
     9  const (
    10  	// expression switch
    11  	switchKindExpr  = iota // switch a {...} or switch 5 {...}
    12  	switchKindTrue         // switch true {...} or switch {...}
    13  	switchKindFalse        // switch false {...}
    14  
    15  	// type switch
    16  	switchKindType // switch a.(type) {...}
    17  )
    18  
    19  const binarySearchMin = 4 // minimum number of cases for binary search
    20  
    21  // An exprSwitch walks an expression switch.
    22  type exprSwitch struct {
    23  	exprname *Node // node for the expression being switched on
    24  	kind     int   // kind of switch statement (switchKind*)
    25  }
    26  
    27  // A typeSwitch walks a type switch.
    28  type typeSwitch struct {
    29  	hashname *Node // node for the hash of the type of the variable being switched on
    30  	facename *Node // node for the concrete type of the variable being switched on
    31  	okname   *Node // boolean node used for comma-ok type assertions
    32  }
    33  
    34  // A caseClause is a single case clause in a switch statement.
    35  type caseClause struct {
    36  	node    *Node  // points at case statement
    37  	ordinal int    // position in switch
    38  	hash    uint32 // hash of a type switch
    39  	// isconst indicates whether this case clause is a constant,
    40  	// for the purposes of the switch code generation.
    41  	// For expression switches, that's generally literals (case 5:, not case x:).
    42  	// For type switches, that's concrete types (case time.Time:), not interfaces (case io.Reader:).
    43  	isconst bool
    44  }
    45  
    46  // caseClauses are all the case clauses in a switch statement.
    47  type caseClauses struct {
    48  	list   []caseClause // general cases
    49  	defjmp *Node        // OGOTO for default case or OBREAK if no default case present
    50  	niljmp *Node        // OGOTO for nil type case in a type switch
    51  }
    52  
    53  // typecheckswitch typechecks a switch statement.
    54  func typecheckswitch(n *Node) {
    55  	lno := lineno
    56  	typecheckslice(n.Ninit.Slice(), Etop)
    57  
    58  	var nilonly string
    59  	var top int
    60  	var t *Type
    61  
    62  	if n.Left != nil && n.Left.Op == OTYPESW {
    63  		// type switch
    64  		top = Etype
    65  		n.Left.Right = typecheck(n.Left.Right, Erv)
    66  		t = n.Left.Right.Type
    67  		if t != nil && !t.IsInterface() {
    68  			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Left.Right, FmtLong))
    69  		}
    70  	} else {
    71  		// expression switch
    72  		top = Erv
    73  		if n.Left != nil {
    74  			n.Left = typecheck(n.Left, Erv)
    75  			n.Left = defaultlit(n.Left, nil)
    76  			t = n.Left.Type
    77  		} else {
    78  			t = Types[TBOOL]
    79  		}
    80  		if t != nil {
    81  			switch {
    82  			case !okforeq[t.Etype]:
    83  				Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
    84  			case t.IsSlice():
    85  				nilonly = "slice"
    86  			case t.IsArray() && !t.IsComparable():
    87  				Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
    88  			case t.IsStruct():
    89  				if f := t.IncomparableField(); f != nil {
    90  					Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), f.Type)
    91  				}
    92  			case t.Etype == TFUNC:
    93  				nilonly = "func"
    94  			case t.IsMap():
    95  				nilonly = "map"
    96  			}
    97  		}
    98  	}
    99  
   100  	n.Type = t
   101  
   102  	var def, niltype *Node
   103  	for _, ncase := range n.List.Slice() {
   104  		setlineno(n)
   105  		if ncase.List.Len() == 0 {
   106  			// default
   107  			if def != nil {
   108  				setlineno(ncase)
   109  				Yyerror("multiple defaults in switch (first at %v)", def.Line())
   110  			} else {
   111  				def = ncase
   112  			}
   113  		} else {
   114  			ls := ncase.List.Slice()
   115  			for i1, n1 := range ls {
   116  				setlineno(n1)
   117  				ls[i1] = typecheck(ls[i1], Erv|Etype)
   118  				n1 = ls[i1]
   119  				if n1.Type == nil || t == nil {
   120  					continue
   121  				}
   122  				setlineno(ncase)
   123  				switch top {
   124  				// expression switch
   125  				case Erv:
   126  					ls[i1] = defaultlit(ls[i1], t)
   127  					n1 = ls[i1]
   128  					switch {
   129  					case n1.Op == OTYPE:
   130  						Yyerror("type %v is not an expression", n1.Type)
   131  					case n1.Type != nil && assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0:
   132  						if n.Left != nil {
   133  							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
   134  						} else {
   135  							Yyerror("invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
   136  						}
   137  					case nilonly != "" && !isnil(n1):
   138  						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
   139  					case t.IsInterface() && !n1.Type.IsInterface() && !n1.Type.IsComparable():
   140  						Yyerror("invalid case %v in switch (incomparable type)", Nconv(n1, FmtLong))
   141  					}
   142  
   143  				// type switch
   144  				case Etype:
   145  					var missing, have *Field
   146  					var ptr int
   147  					switch {
   148  					case n1.Op == OLITERAL && n1.Type.IsKind(TNIL):
   149  						// case nil:
   150  						if niltype != nil {
   151  							Yyerror("multiple nil cases in type switch (first at %v)", niltype.Line())
   152  						} else {
   153  							niltype = ncase
   154  						}
   155  					case n1.Op != OTYPE && n1.Type != nil: // should this be ||?
   156  						Yyerror("%v is not a type", Nconv(n1, FmtLong))
   157  						// reset to original type
   158  						n1 = n.Left.Right
   159  						ls[i1] = n1
   160  					case !n1.Type.IsInterface() && t.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr):
   161  						if have != nil && !missing.Broke && !have.Broke {
   162  							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym, have.Sym, Tconv(have.Type, FmtShort), missing.Sym, Tconv(missing.Type, FmtShort))
   163  						} else if !missing.Broke {
   164  							Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym)
   165  						}
   166  					}
   167  				}
   168  			}
   169  		}
   170  
   171  		if top == Etype && n.Type != nil {
   172  			ll := ncase.List
   173  			if ncase.Rlist.Len() != 0 {
   174  				nvar := ncase.Rlist.First()
   175  				if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) {
   176  					// single entry type switch
   177  					nvar.Name.Param.Ntype = typenod(ll.First().Type)
   178  				} else {
   179  					// multiple entry type switch or default
   180  					nvar.Name.Param.Ntype = typenod(n.Type)
   181  				}
   182  
   183  				nvar = typecheck(nvar, Erv|Easgn)
   184  				ncase.Rlist.SetIndex(0, nvar)
   185  			}
   186  		}
   187  
   188  		typecheckslice(ncase.Nbody.Slice(), Etop)
   189  	}
   190  
   191  	lineno = lno
   192  }
   193  
   194  // walkswitch walks a switch statement.
   195  func walkswitch(sw *Node) {
   196  	// convert switch {...} to switch true {...}
   197  	if sw.Left == nil {
   198  		sw.Left = Nodbool(true)
   199  		sw.Left = typecheck(sw.Left, Erv)
   200  	}
   201  
   202  	if sw.Left.Op == OTYPESW {
   203  		var s typeSwitch
   204  		s.walk(sw)
   205  	} else {
   206  		var s exprSwitch
   207  		s.walk(sw)
   208  	}
   209  }
   210  
   211  // walk generates an AST implementing sw.
   212  // sw is an expression switch.
   213  // The AST is generally of the form of a linear
   214  // search using if..goto, although binary search
   215  // is used with long runs of constants.
   216  func (s *exprSwitch) walk(sw *Node) {
   217  	casebody(sw, nil)
   218  
   219  	cond := sw.Left
   220  	sw.Left = nil
   221  
   222  	s.kind = switchKindExpr
   223  	if Isconst(cond, CTBOOL) {
   224  		s.kind = switchKindTrue
   225  		if !cond.Val().U.(bool) {
   226  			s.kind = switchKindFalse
   227  		}
   228  	}
   229  
   230  	cond = walkexpr(cond, &sw.Ninit)
   231  	t := sw.Type
   232  	if t == nil {
   233  		return
   234  	}
   235  
   236  	// convert the switch into OIF statements
   237  	var cas []*Node
   238  	if s.kind == switchKindTrue || s.kind == switchKindFalse {
   239  		s.exprname = Nodbool(s.kind == switchKindTrue)
   240  	} else if consttype(cond) >= 0 {
   241  		// leave constants to enable dead code elimination (issue 9608)
   242  		s.exprname = cond
   243  	} else {
   244  		s.exprname = temp(cond.Type)
   245  		cas = []*Node{Nod(OAS, s.exprname, cond)}
   246  		typecheckslice(cas, Etop)
   247  	}
   248  
   249  	// Enumerate the cases and prepare the default case.
   250  	clauses := s.genCaseClauses(sw.List.Slice())
   251  	sw.List.Set(nil)
   252  	cc := clauses.list
   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].isconst {
   258  			a := s.walkCases(cc[:1])
   259  			cas = append(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].isconst; run++ {
   267  		}
   268  
   269  		// sort and compile constants
   270  		sort.Sort(caseClauseByConstVal(cc[:run]))
   271  		a := s.walkCases(cc[:run])
   272  		cas = append(cas, a)
   273  		cc = cc[run:]
   274  	}
   275  
   276  	// handle default case
   277  	if nerrors == 0 {
   278  		cas = append(cas, clauses.defjmp)
   279  		sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
   280  		walkstmtlist(sw.Nbody.Slice())
   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 []*Node
   289  		for _, c := range cc {
   290  			n := c.node
   291  			lno := 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  				a.Left = 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  				a.Left = typecheck(a.Left, Erv)
   303  			}
   304  			a.Nbody.Set1(n.Right) // goto l
   305  
   306  			cas = append(cas, a)
   307  			lineno = 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 caseClauseByConstVal.
   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  	a.Left = typecheck(a.Left, Erv)
   326  	a.Nbody.Set1(s.walkCases(cc[:half]))
   327  	a.Rlist.Set1(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.Len() == 0 {
   336  		return
   337  	}
   338  
   339  	lno := setlineno(sw)
   340  
   341  	var cas []*Node  // cases
   342  	var stat []*Node // statements
   343  	var def *Node    // defaults
   344  	br := Nod(OBREAK, nil, nil)
   345  
   346  	for i, n := range sw.List.Slice() {
   347  		setlineno(n)
   348  		if n.Op != OXCASE {
   349  			Fatalf("casebody %v", n.Op)
   350  		}
   351  		n.Op = OCASE
   352  		needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
   353  
   354  		jmp := Nod(OGOTO, autolabel(".s"), nil)
   355  		switch n.List.Len() {
   356  		case 0:
   357  			// default
   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  		case 1:
   365  			// one case -- reuse OCASE node
   366  			n.Left = n.List.First()
   367  			n.Right = jmp
   368  			n.List.Set(nil)
   369  			cas = append(cas, n)
   370  		default:
   371  			// expand multi-valued cases
   372  			for _, n1 := range n.List.Slice() {
   373  				cas = append(cas, Nod(OCASE, n1, jmp))
   374  			}
   375  		}
   376  
   377  		stat = append(stat, Nod(OLABEL, jmp.Left, nil))
   378  		if typeswvar != nil && needvar && n.Rlist.Len() != 0 {
   379  			l := []*Node{
   380  				Nod(ODCL, n.Rlist.First(), nil),
   381  				Nod(OAS, n.Rlist.First(), typeswvar),
   382  			}
   383  			typecheckslice(l, Etop)
   384  			stat = append(stat, l...)
   385  		}
   386  		stat = append(stat, n.Nbody.Slice()...)
   387  
   388  		// botch - shouldn't fall through declaration
   389  		last := stat[len(stat)-1]
   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 i+1 >= sw.List.Len() {
   397  				setlineno(last)
   398  				Yyerror("cannot fallthrough final case in switch")
   399  			}
   400  
   401  			last.Op = OFALL
   402  		} else {
   403  			stat = append(stat, br)
   404  		}
   405  	}
   406  
   407  	stat = append(stat, br)
   408  	if def != nil {
   409  		cas = append(cas, def)
   410  	}
   411  
   412  	sw.List.Set(cas)
   413  	sw.Nbody.Set(stat)
   414  	lineno = lno
   415  }
   416  
   417  // genCaseClauses generates the caseClauses value for clauses.
   418  func (s *exprSwitch) genCaseClauses(clauses []*Node) caseClauses {
   419  	var cc caseClauses
   420  	for _, n := range clauses {
   421  		if n.Left == nil {
   422  			// default case
   423  			if cc.defjmp != nil {
   424  				Fatalf("duplicate default case not detected during typechecking")
   425  			}
   426  			cc.defjmp = n.Right
   427  			continue
   428  		}
   429  		c := caseClause{node: n, ordinal: len(cc.list)}
   430  		switch consttype(n.Left) {
   431  		case CTFLT, CTINT, CTRUNE, CTSTR:
   432  			c.isconst = true
   433  		}
   434  		cc.list = append(cc.list, c)
   435  	}
   436  
   437  	if cc.defjmp == nil {
   438  		cc.defjmp = Nod(OBREAK, nil, nil)
   439  	}
   440  
   441  	// diagnose duplicate cases
   442  	s.checkDupCases(cc.list)
   443  	return cc
   444  }
   445  
   446  // genCaseClauses generates the caseClauses value for clauses.
   447  func (s *typeSwitch) genCaseClauses(clauses []*Node) caseClauses {
   448  	var cc caseClauses
   449  	for _, n := range clauses {
   450  		switch {
   451  		case n.Left == nil:
   452  			// default case
   453  			if cc.defjmp != nil {
   454  				Fatalf("duplicate default case not detected during typechecking")
   455  			}
   456  			cc.defjmp = n.Right
   457  			continue
   458  		case n.Left.Op == OLITERAL:
   459  			// nil case in type switch
   460  			if cc.niljmp != nil {
   461  				Fatalf("duplicate nil case not detected during typechecking")
   462  			}
   463  			cc.niljmp = n.Right
   464  			continue
   465  		}
   466  
   467  		// general case
   468  		c := caseClause{
   469  			node:    n,
   470  			ordinal: len(cc.list),
   471  			isconst: !n.Left.Type.IsInterface(),
   472  			hash:    typehash(n.Left.Type),
   473  		}
   474  		cc.list = append(cc.list, c)
   475  	}
   476  
   477  	if cc.defjmp == nil {
   478  		cc.defjmp = Nod(OBREAK, nil, nil)
   479  	}
   480  
   481  	// diagnose duplicate cases
   482  	s.checkDupCases(cc.list)
   483  	return cc
   484  }
   485  
   486  func (s *typeSwitch) checkDupCases(cc []caseClause) {
   487  	if len(cc) < 2 {
   488  		return
   489  	}
   490  	// We store seen types in a map keyed by type hash.
   491  	// It is possible, but very unlikely, for multiple distinct types to have the same hash.
   492  	seen := make(map[uint32][]*Node)
   493  	// To avoid many small allocations of length 1 slices,
   494  	// also set up a single large slice to slice into.
   495  	nn := make([]*Node, 0, len(cc))
   496  Outer:
   497  	for _, c := range cc {
   498  		prev, ok := seen[c.hash]
   499  		if !ok {
   500  			// First entry for this hash.
   501  			nn = append(nn, c.node)
   502  			seen[c.hash] = nn[len(nn)-1 : len(nn):len(nn)]
   503  			continue
   504  		}
   505  		for _, n := range prev {
   506  			if Eqtype(n.Left.Type, c.node.Left.Type) {
   507  				yyerrorl(c.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c.node.Left.Type, n.Line())
   508  				// avoid double-reporting errors
   509  				continue Outer
   510  			}
   511  		}
   512  		seen[c.hash] = append(seen[c.hash], c.node)
   513  	}
   514  }
   515  
   516  func (s *exprSwitch) checkDupCases(cc []caseClause) {
   517  	if len(cc) < 2 {
   518  		return
   519  	}
   520  	// The common case is that s's expression is not an interface.
   521  	// In that case, all constant clauses have the same type,
   522  	// so checking for duplicates can be done solely by value.
   523  	if !s.exprname.Type.IsInterface() {
   524  		seen := make(map[interface{}]*Node)
   525  		for _, c := range cc {
   526  			// Can't check for duplicates that aren't constants, per the spec. Issue 15896.
   527  			// Don't check for duplicate bools. Although the spec allows it,
   528  			// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
   529  			// (2) it would disallow useful things like
   530  			//       case GOARCH == "arm" && GOARM == "5":
   531  			//       case GOARCH == "arm":
   532  			//     which would both evaluate to false for non-ARM compiles.
   533  			if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
   534  				continue
   535  			}
   536  			val := c.node.Left.Val().Interface()
   537  			prev, dup := seen[val]
   538  			if !dup {
   539  				seen[val] = c.node
   540  				continue
   541  			}
   542  			setlineno(c.node)
   543  			Yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line())
   544  		}
   545  		return
   546  	}
   547  	// s's expression is an interface. This is fairly rare, so keep this simple.
   548  	// Duplicates are only duplicates if they have the same type and the same value.
   549  	type typeVal struct {
   550  		typ string
   551  		val interface{}
   552  	}
   553  	seen := make(map[typeVal]*Node)
   554  	for _, c := range cc {
   555  		if ct := consttype(c.node.Left); ct < 0 || ct == CTBOOL {
   556  			continue
   557  		}
   558  		n := c.node.Left
   559  		tv := typeVal{
   560  			// Tconv here serves to completely describe the type.
   561  			// See the comments in func typehash.
   562  			typ: Tconv(n.Type, FmtLeft|FmtUnsigned),
   563  			val: n.Val().Interface(),
   564  		}
   565  		prev, dup := seen[tv]
   566  		if !dup {
   567  			seen[tv] = c.node
   568  			continue
   569  		}
   570  		setlineno(c.node)
   571  		Yyerror("duplicate case %v in switch\n\tprevious case at %v", prev.Left, prev.Line())
   572  	}
   573  }
   574  
   575  // walk generates an AST that implements sw,
   576  // where sw is a type switch.
   577  // The AST is generally of the form of a linear
   578  // search using if..goto, although binary search
   579  // is used with long runs of concrete types.
   580  func (s *typeSwitch) walk(sw *Node) {
   581  	cond := sw.Left
   582  	sw.Left = nil
   583  
   584  	if cond == nil {
   585  		sw.List.Set(nil)
   586  		return
   587  	}
   588  	if cond.Right == nil {
   589  		setlineno(sw)
   590  		Yyerror("type switch must have an assignment")
   591  		return
   592  	}
   593  
   594  	cond.Right = walkexpr(cond.Right, &sw.Ninit)
   595  	if !cond.Right.Type.IsInterface() {
   596  		Yyerror("type switch must be on an interface")
   597  		return
   598  	}
   599  
   600  	var cas []*Node
   601  
   602  	// predeclare temporary variables and the boolean var
   603  	s.facename = temp(cond.Right.Type)
   604  
   605  	a := Nod(OAS, s.facename, cond.Right)
   606  	a = typecheck(a, Etop)
   607  	cas = append(cas, a)
   608  
   609  	s.okname = temp(Types[TBOOL])
   610  	s.okname = typecheck(s.okname, Erv)
   611  
   612  	s.hashname = temp(Types[TUINT32])
   613  	s.hashname = typecheck(s.hashname, Erv)
   614  
   615  	// set up labels and jumps
   616  	casebody(sw, s.facename)
   617  
   618  	clauses := s.genCaseClauses(sw.List.Slice())
   619  	sw.List.Set(nil)
   620  	def := clauses.defjmp
   621  
   622  	// For empty interfaces, do:
   623  	//     if e._type == nil {
   624  	//         do nil case if it exists, otherwise default
   625  	//     }
   626  	//     h := e._type.hash
   627  	// Use a similar strategy for non-empty interfaces.
   628  
   629  	// Get interface descriptor word.
   630  	typ := Nod(OITAB, s.facename, nil)
   631  
   632  	// Check for nil first.
   633  	i := Nod(OIF, nil, nil)
   634  	i.Left = Nod(OEQ, typ, nodnil())
   635  	if clauses.niljmp != nil {
   636  		// Do explicit nil case right here.
   637  		i.Nbody.Set1(clauses.niljmp)
   638  	} else {
   639  		// Jump to default case.
   640  		lbl := autolabel(".s")
   641  		i.Nbody.Set1(Nod(OGOTO, lbl, nil))
   642  		// Wrap default case with label.
   643  		blk := Nod(OBLOCK, nil, nil)
   644  		blk.List.Set([]*Node{Nod(OLABEL, lbl, nil), def})
   645  		def = blk
   646  	}
   647  	i.Left = typecheck(i.Left, Erv)
   648  	cas = append(cas, i)
   649  
   650  	if !cond.Right.Type.IsEmptyInterface() {
   651  		// Load type from itab.
   652  		typ = itabType(typ)
   653  	}
   654  	// Load hash from type.
   655  	h := NodSym(ODOTPTR, typ, nil)
   656  	h.Type = Types[TUINT32]
   657  	h.Typecheck = 1
   658  	h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
   659  	h.Bounded = true                // guaranteed not to fault
   660  	a = Nod(OAS, s.hashname, h)
   661  	a = typecheck(a, Etop)
   662  	cas = append(cas, a)
   663  
   664  	cc := clauses.list
   665  
   666  	// insert type equality check into each case block
   667  	for _, c := range cc {
   668  		c.node.Right = s.typeone(c.node)
   669  	}
   670  
   671  	// generate list of if statements, binary search for constant sequences
   672  	for len(cc) > 0 {
   673  		if !cc[0].isconst {
   674  			n := cc[0].node
   675  			cas = append(cas, n.Right)
   676  			cc = cc[1:]
   677  			continue
   678  		}
   679  
   680  		// identify run of constants
   681  		var run int
   682  		for run = 1; run < len(cc) && cc[run].isconst; run++ {
   683  		}
   684  
   685  		// sort by hash
   686  		sort.Sort(caseClauseByType(cc[:run]))
   687  
   688  		// for debugging: linear search
   689  		if false {
   690  			for i := 0; i < run; i++ {
   691  				n := cc[i].node
   692  				cas = append(cas, n.Right)
   693  			}
   694  			continue
   695  		}
   696  
   697  		// combine adjacent cases with the same hash
   698  		ncase := 0
   699  		for i := 0; i < run; i++ {
   700  			ncase++
   701  			hash := []*Node{cc[i].node.Right}
   702  			for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
   703  				hash = append(hash, cc[j].node.Right)
   704  			}
   705  			cc[i].node.Right = liststmt(hash)
   706  		}
   707  
   708  		// binary search among cases to narrow by hash
   709  		cas = append(cas, s.walkCases(cc[:ncase]))
   710  		cc = cc[ncase:]
   711  	}
   712  
   713  	// handle default case
   714  	if nerrors == 0 {
   715  		cas = append(cas, def)
   716  		sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
   717  		sw.List.Set(nil)
   718  		walkstmtlist(sw.Nbody.Slice())
   719  	}
   720  }
   721  
   722  // typeone generates an AST that jumps to the
   723  // case body if the variable is of type t.
   724  func (s *typeSwitch) typeone(t *Node) *Node {
   725  	var name *Node
   726  	var init []*Node
   727  	if t.Rlist.Len() == 0 {
   728  		name = nblank
   729  		nblank = typecheck(nblank, Erv|Easgn)
   730  	} else {
   731  		name = t.Rlist.First()
   732  		init = []*Node{Nod(ODCL, name, nil)}
   733  		a := Nod(OAS, name, nil)
   734  		a = typecheck(a, Etop)
   735  		init = append(init, a)
   736  	}
   737  
   738  	a := Nod(OAS2, nil, nil)
   739  	a.List.Set([]*Node{name, s.okname}) // name, ok =
   740  	b := Nod(ODOTTYPE, s.facename, nil)
   741  	b.Type = t.Left.Type // interface.(type)
   742  	a.Rlist.Set1(b)
   743  	a = typecheck(a, Etop)
   744  	init = append(init, a)
   745  
   746  	c := Nod(OIF, nil, nil)
   747  	c.Left = s.okname
   748  	c.Nbody.Set1(t.Right) // if ok { goto l }
   749  
   750  	return liststmt(append(init, c))
   751  }
   752  
   753  // walkCases generates an AST implementing the cases in cc.
   754  func (s *typeSwitch) walkCases(cc []caseClause) *Node {
   755  	if len(cc) < binarySearchMin {
   756  		var cas []*Node
   757  		for _, c := range cc {
   758  			n := c.node
   759  			if !c.isconst {
   760  				Fatalf("typeSwitch walkCases")
   761  			}
   762  			a := Nod(OIF, nil, nil)
   763  			a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
   764  			a.Left = typecheck(a.Left, Erv)
   765  			a.Nbody.Set1(n.Right)
   766  			cas = append(cas, a)
   767  		}
   768  		return liststmt(cas)
   769  	}
   770  
   771  	// find the middle and recur
   772  	half := len(cc) / 2
   773  	a := Nod(OIF, nil, nil)
   774  	a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
   775  	a.Left = typecheck(a.Left, Erv)
   776  	a.Nbody.Set1(s.walkCases(cc[:half]))
   777  	a.Rlist.Set1(s.walkCases(cc[half:]))
   778  	return a
   779  }
   780  
   781  // caseClauseByConstVal sorts clauses by constant value to enable binary search.
   782  type caseClauseByConstVal []caseClause
   783  
   784  func (x caseClauseByConstVal) Len() int      { return len(x) }
   785  func (x caseClauseByConstVal) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   786  func (x caseClauseByConstVal) Less(i, j int) bool {
   787  	v1 := x[i].node.Left.Val().U
   788  	v2 := x[j].node.Left.Val().U
   789  
   790  	switch v1 := v1.(type) {
   791  	case *Mpflt:
   792  		return v1.Cmp(v2.(*Mpflt)) < 0
   793  	case *Mpint:
   794  		return v1.Cmp(v2.(*Mpint)) < 0
   795  	case string:
   796  		// Sort strings by length and then by value.
   797  		// It is much cheaper to compare lengths than values,
   798  		// and all we need here is consistency.
   799  		// We respect this sorting in exprSwitch.walkCases.
   800  		a := v1
   801  		b := v2.(string)
   802  		if len(a) != len(b) {
   803  			return len(a) < len(b)
   804  		}
   805  		return a < b
   806  	}
   807  
   808  	Fatalf("caseClauseByConstVal passed bad clauses %v < %v", x[i].node.Left, x[j].node.Left)
   809  	return false
   810  }
   811  
   812  type caseClauseByType []caseClause
   813  
   814  func (x caseClauseByType) Len() int      { return len(x) }
   815  func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
   816  func (x caseClauseByType) Less(i, j int) bool {
   817  	c1, c2 := x[i], x[j]
   818  	// sort by hash code, then ordinal (for the rare case of hash collisions)
   819  	if c1.hash != c2.hash {
   820  		return c1.hash < c2.hash
   821  	}
   822  	return c1.ordinal < c2.ordinal
   823  }