blob: 3b08b13508d4a812cfa831a00c02b115a2d58f5a [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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
5package gc
6
7import (
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +00008 "sort"
9 "strconv"
Russ Cox8c195bd2015-02-13 14:40:36 -050010)
11
12const (
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000013 // expression switch
14 switchKindExpr = iota // switch a {...} or switch 5 {...}
15 switchKindTrue // switch true {...} or switch {...}
16 switchKindFalse // switch false {...}
17
18 // type switch
19 switchKindType // switch a.(type) {...}
Russ Cox8c195bd2015-02-13 14:40:36 -050020)
21
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000022const (
23 caseKindDefault = iota // default:
24
25 // expression switch
26 caseKindExprConst // case 5:
27 caseKindExprVar // case x:
28
29 // type switch
30 caseKindTypeNil // case nil:
31 caseKindTypeConst // case time.Time: (concrete type, has type hash)
32 caseKindTypeVar // case io.Reader: (interface type)
33)
34
35const binarySearchMin = 4 // minimum number of cases for binary search
36
37// An exprSwitch walks an expression switch.
38type exprSwitch struct {
39 exprname *Node // node for the expression being switched on
40 kind int // kind of switch statement (switchKind*)
Russ Cox8c195bd2015-02-13 14:40:36 -050041}
42
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000043// A typeSwitch walks a type switch.
44type typeSwitch struct {
45 hashname *Node // node for the hash of the type of the variable being switched on
46 facename *Node // node for the concrete type of the variable being switched on
47 okname *Node // boolean node used for comma-ok type assertions
48}
Russ Cox8c195bd2015-02-13 14:40:36 -050049
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000050// A caseClause is a single case clause in a switch statement.
51type caseClause struct {
52 node *Node // points at case statement
53 ordinal int // position in switch
54 hash uint32 // hash of a type switch
55 typ uint8 // type of case
56}
Russ Cox8c195bd2015-02-13 14:40:36 -050057
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000058// typecheckswitch typechecks a switch statement.
59func typecheckswitch(n *Node) {
Robert Griesemerc41608f2016-03-02 17:34:42 -080060 lno := lineno
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -070061 typecheckslice(n.Ninit.Slice(), Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -050062
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000063 var nilonly string
64 var top int
65 var t *Type
Russ Cox8c195bd2015-02-13 14:40:36 -050066
Russ Cox66be1482015-05-26 21:30:20 -040067 if n.Left != nil && n.Left.Op == OTYPESW {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000068 // type switch
69 top = Etype
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -070070 n.Left.Right = typecheck(n.Left.Right, Erv)
Russ Cox66be1482015-05-26 21:30:20 -040071 t = n.Left.Right.Type
Matthew Dempsky3efefd92016-03-30 14:56:08 -070072 if t != nil && !t.IsInterface() {
Matthew Dempsky63142022016-03-15 13:06:58 -070073 Yyerror("cannot type switch on non-interface value %v", Nconv(n.Left.Right, FmtLong))
Russ Cox8c195bd2015-02-13 14:40:36 -050074 }
Russ Cox8c195bd2015-02-13 14:40:36 -050075 } else {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000076 // expression switch
77 top = Erv
Russ Cox66be1482015-05-26 21:30:20 -040078 if n.Left != nil {
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -070079 n.Left = typecheck(n.Left, Erv)
80 n.Left = defaultlit(n.Left, nil)
Russ Cox66be1482015-05-26 21:30:20 -040081 t = n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -050082 } else {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000083 t = Types[TBOOL]
84 }
85 if t != nil {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000086 switch {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +000087 case !okforeq[t.Etype]:
Matthew Dempsky63142022016-03-15 13:06:58 -070088 Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
Matthew Dempsky077902d2016-04-01 11:22:03 -070089 case t.IsSlice():
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000090 nilonly = "slice"
Matthew Dempsky077902d2016-04-01 11:22:03 -070091 case t.IsArray() && !t.IsComparable():
Matthew Dempsky63142022016-03-15 13:06:58 -070092 Yyerror("cannot switch on %v", Nconv(n.Left, FmtLong))
Matthew Dempsky077902d2016-04-01 11:22:03 -070093 case t.IsStruct():
94 if f := t.IncomparableField(); f != nil {
95 Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, FmtLong), f.Type)
96 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000097 case t.Etype == TFUNC:
98 nilonly = "func"
Matthew Dempsky3efefd92016-03-30 14:56:08 -070099 case t.IsMap():
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000100 nilonly = "map"
101 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500102 }
103 }
104
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000105 n.Type = t
106
107 var def *Node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800108 for _, ncase := range n.List.Slice() {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000109 setlineno(n)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800110 if ncase.List.Len() == 0 {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000111 // default
112 if def != nil {
113 Yyerror("multiple defaults in switch (first at %v)", def.Line())
114 } else {
115 def = ncase
116 }
117 } else {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800118 ls := ncase.List.Slice()
119 for i1, n1 := range ls {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800120 setlineno(n1)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700121 ls[i1] = typecheck(ls[i1], Erv|Etype)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800122 n1 = ls[i1]
123 if n1.Type == nil || t == nil {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000124 continue
125 }
126 setlineno(ncase)
127 switch top {
128 // expression switch
129 case Erv:
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700130 ls[i1] = defaultlit(ls[i1], t)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800131 n1 = ls[i1]
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000132 switch {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800133 case n1.Op == OTYPE:
134 Yyerror("type %v is not an expression", n1.Type)
135 case n1.Type != nil && assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0:
Russ Cox66be1482015-05-26 21:30:20 -0400136 if n.Left != nil {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800137 Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000138 } else {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800139 Yyerror("invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000140 }
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800141 case nilonly != "" && !isnil(n1):
142 Yyerror("invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
Matthew Dempsky077902d2016-04-01 11:22:03 -0700143 case t.IsInterface() && !n1.Type.IsInterface() && !n1.Type.IsComparable():
Matthew Dempsky63142022016-03-15 13:06:58 -0700144 Yyerror("invalid case %v in switch (incomparable type)", Nconv(n1, FmtLong))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000145 }
146
147 // type switch
148 case Etype:
Matthew Dempsky2e936902016-03-14 01:20:49 -0700149 var missing, have *Field
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000150 var ptr int
151 switch {
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700152 case n1.Op == OLITERAL && n1.Type.IsKind(TNIL):
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800153 case n1.Op != OTYPE && n1.Type != nil: // should this be ||?
Matthew Dempsky63142022016-03-15 13:06:58 -0700154 Yyerror("%v is not a type", Nconv(n1, FmtLong))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000155 // reset to original type
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800156 n1 = n.Left.Right
157 ls[i1] = n1
Matthew Dempsky3efefd92016-03-30 14:56:08 -0700158 case !n1.Type.IsInterface() && t.IsInterface() && !implements(n1.Type, t, &missing, &have, &ptr):
Dave Cheney89377802015-09-07 10:37:26 +1000159 if have != nil && !missing.Broke && !have.Broke {
Matthew Dempsky63142022016-03-15 13:06:58 -0700160 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))
Dave Cheney89377802015-09-07 10:37:26 +1000161 } else if !missing.Broke {
Matthew Dempsky63142022016-03-15 13:06:58 -0700162 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, FmtLong), n1.Type, missing.Sym)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000163 }
164 }
165 }
166 }
167 }
168
169 if top == Etype && n.Type != nil {
Ian Lance Taylor65c4b552016-03-04 17:28:07 -0800170 ll := ncase.List
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800171 if ncase.Rlist.Len() != 0 {
172 nvar := ncase.Rlist.First()
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700173 if ll.Len() == 1 && ll.First().Type != nil && !ll.First().Type.IsKind(TNIL) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000174 // single entry type switch
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800175 nvar.Name.Param.Ntype = typenod(ll.First().Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000176 } else {
177 // multiple entry type switch or default
Russ Cox3c3019a2015-05-27 00:44:05 -0400178 nvar.Name.Param.Ntype = typenod(n.Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000179 }
180
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700181 nvar = typecheck(nvar, Erv|Easgn)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800182 ncase.Rlist.SetIndex(0, nvar)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000183 }
184 }
185
Josh Bleecher Snyderec7c4942016-03-19 17:02:01 -0700186 typecheckslice(ncase.Nbody.Slice(), Etop)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000187 }
188
Robert Griesemerc41608f2016-03-02 17:34:42 -0800189 lineno = lno
Russ Cox8c195bd2015-02-13 14:40:36 -0500190}
191
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000192// walkswitch walks a switch statement.
193func walkswitch(sw *Node) {
194 // convert switch {...} to switch true {...}
Russ Cox66be1482015-05-26 21:30:20 -0400195 if sw.Left == nil {
196 sw.Left = Nodbool(true)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700197 sw.Left = typecheck(sw.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000198 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500199
Russ Cox66be1482015-05-26 21:30:20 -0400200 if sw.Left.Op == OTYPESW {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000201 var s typeSwitch
202 s.walk(sw)
203 } else {
204 var s exprSwitch
205 s.walk(sw)
206 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500207}
208
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000209// walk generates an AST implementing sw.
210// sw is an expression switch.
211// The AST is generally of the form of a linear
212// search using if..goto, although binary search
213// is used with long runs of constants.
214func (s *exprSwitch) walk(sw *Node) {
215 casebody(sw, nil)
216
Russ Cox66be1482015-05-26 21:30:20 -0400217 cond := sw.Left
218 sw.Left = nil
219
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000220 s.kind = switchKindExpr
Russ Cox66be1482015-05-26 21:30:20 -0400221 if Isconst(cond, CTBOOL) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000222 s.kind = switchKindTrue
Russ Cox81d58102015-05-27 00:47:05 -0400223 if !cond.Val().U.(bool) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000224 s.kind = switchKindFalse
225 }
226 }
227
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700228 cond = walkexpr(cond, &sw.Ninit)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000229 t := sw.Type
230 if t == nil {
231 return
232 }
233
234 // convert the switch into OIF statements
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800235 var cas []*Node
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000236 if s.kind == switchKindTrue || s.kind == switchKindFalse {
237 s.exprname = Nodbool(s.kind == switchKindTrue)
Russ Cox66be1482015-05-26 21:30:20 -0400238 } else if consttype(cond) >= 0 {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000239 // leave constants to enable dead code elimination (issue 9608)
Russ Cox66be1482015-05-26 21:30:20 -0400240 s.exprname = cond
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000241 } else {
Russ Cox66be1482015-05-26 21:30:20 -0400242 s.exprname = temp(cond.Type)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800243 cas = []*Node{Nod(OAS, s.exprname, cond)}
244 typecheckslice(cas, Etop)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000245 }
246
247 // enumerate the cases, and lop off the default case
248 cc := caseClauses(sw, s.kind)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800249 sw.List.Set(nil)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000250 var def *Node
251 if len(cc) > 0 && cc[0].typ == caseKindDefault {
252 def = cc[0].node.Right
253 cc = cc[1:]
254 } else {
255 def = Nod(OBREAK, nil, nil)
256 }
257
258 // handle the cases in order
259 for len(cc) > 0 {
260 // deal with expressions one at a time
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000261 if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000262 a := s.walkCases(cc[:1])
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800263 cas = append(cas, a)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000264 cc = cc[1:]
265 continue
266 }
267
268 // do binary search on runs of constants
269 var run int
270 for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
271 }
272
273 // sort and compile constants
274 sort.Sort(caseClauseByExpr(cc[:run]))
275 a := s.walkCases(cc[:run])
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800276 cas = append(cas, a)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000277 cc = cc[run:]
278 }
279
280 // handle default case
281 if nerrors == 0 {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800282 cas = append(cas, def)
283 sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800284 walkstmtlist(sw.Nbody.Slice())
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000285 }
286}
287
288// walkCases generates an AST implementing the cases in cc.
289func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
290 if len(cc) < binarySearchMin {
291 // linear search
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800292 var cas []*Node
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000293 for _, c := range cc {
294 n := c.node
Robert Griesemerc41608f2016-03-02 17:34:42 -0800295 lno := setlineno(n)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000296
297 a := Nod(OIF, nil, nil)
298 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 {
Russ Cox66be1482015-05-26 21:30:20 -0400299 a.Left = Nod(OEQ, s.exprname, n.Left) // if name == val
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700300 a.Left = typecheck(a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000301 } else if s.kind == switchKindTrue {
Russ Cox66be1482015-05-26 21:30:20 -0400302 a.Left = n.Left // if val
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000303 } else {
304 // s.kind == switchKindFalse
Russ Cox66be1482015-05-26 21:30:20 -0400305 a.Left = Nod(ONOT, n.Left, nil) // if !val
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700306 a.Left = typecheck(a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000307 }
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800308 a.Nbody.Set1(n.Right) // goto l
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000309
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800310 cas = append(cas, a)
Robert Griesemerc41608f2016-03-02 17:34:42 -0800311 lineno = lno
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000312 }
313 return liststmt(cas)
314 }
315
316 // find the middle and recur
317 half := len(cc) / 2
318 a := Nod(OIF, nil, nil)
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700319 mid := cc[half-1].node.Left
320 le := Nod(OLE, s.exprname, mid)
321 if Isconst(mid, CTSTR) {
322 // Search by length and then by value; see exprcmp.
323 lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
324 leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
Russ Cox66be1482015-05-26 21:30:20 -0400325 a.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700326 } else {
Russ Cox66be1482015-05-26 21:30:20 -0400327 a.Left = le
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700328 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700329 a.Left = typecheck(a.Left, Erv)
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800330 a.Nbody.Set1(s.walkCases(cc[:half]))
331 a.Rlist.Set1(s.walkCases(cc[half:]))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000332 return a
333}
334
335// casebody builds separate lists of statements and cases.
336// It makes labels between cases and statements
337// and deals with fallthrough, break, and unreachable statements.
Russ Cox8c195bd2015-02-13 14:40:36 -0500338func casebody(sw *Node, typeswvar *Node) {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800339 if sw.List.Len() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500340 return
341 }
342
Russ Cox382b44e2015-02-23 16:07:24 -0500343 lno := setlineno(sw)
Russ Cox8c195bd2015-02-13 14:40:36 -0500344
Ian Lance Taylor65c4b552016-03-04 17:28:07 -0800345 var cas []*Node // cases
346 var stat []*Node // statements
347 var def *Node // defaults
Russ Cox382b44e2015-02-23 16:07:24 -0500348 br := Nod(OBREAK, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500349
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800350 for i, n := range sw.List.Slice() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500351 setlineno(n)
352 if n.Op != OXCASE {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -0800353 Fatalf("casebody %v", Oconv(n.Op, 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500354 }
355 n.Op = OCASE
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800356 needvar := n.List.Len() != 1 || n.List.First().Op == OLITERAL
Russ Cox8c195bd2015-02-13 14:40:36 -0500357
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000358 jmp := Nod(OGOTO, newCaseLabel(), nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800359 if n.List.Len() == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500360 if def != nil {
361 Yyerror("more than one default case")
362 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500363 // reuse original default case
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000364 n.Right = jmp
Russ Cox8c195bd2015-02-13 14:40:36 -0500365 def = n
366 }
367
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800368 if n.List.Len() == 1 {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000369 // one case -- reuse OCASE node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800370 n.Left = n.List.First()
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000371 n.Right = jmp
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800372 n.List.Set(nil)
Ian Lance Taylor65c4b552016-03-04 17:28:07 -0800373 cas = append(cas, n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500374 } else {
375 // expand multi-valued cases
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800376 for _, n1 := range n.List.Slice() {
377 cas = append(cas, Nod(OCASE, n1, jmp))
Russ Cox8c195bd2015-02-13 14:40:36 -0500378 }
379 }
380
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800381 stat = append(stat, Nod(OLABEL, jmp.Left, nil))
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800382 if typeswvar != nil && needvar && n.Rlist.Len() != 0 {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800383 l := []*Node{
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800384 Nod(ODCL, n.Rlist.First(), nil),
385 Nod(OAS, n.Rlist.First(), typeswvar),
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800386 }
387 typecheckslice(l, Etop)
388 stat = append(stat, l...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500389 }
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800390 stat = append(stat, n.Nbody.Slice()...)
Russ Cox8c195bd2015-02-13 14:40:36 -0500391
Eric Engestrom7a8caf72016-04-03 12:43:27 +0100392 // botch - shouldn't fall through declaration
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800393 last := stat[len(stat)-1]
Russ Cox8c195bd2015-02-13 14:40:36 -0500394 if last.Xoffset == n.Xoffset && last.Op == OXFALL {
395 if typeswvar != nil {
396 setlineno(last)
397 Yyerror("cannot fallthrough in type switch")
398 }
399
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -0800400 if i+1 >= sw.List.Len() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500401 setlineno(last)
402 Yyerror("cannot fallthrough final case in switch")
403 }
404
405 last.Op = OFALL
406 } else {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800407 stat = append(stat, br)
Russ Cox8c195bd2015-02-13 14:40:36 -0500408 }
409 }
410
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800411 stat = append(stat, br)
Russ Cox8c195bd2015-02-13 14:40:36 -0500412 if def != nil {
Ian Lance Taylor65c4b552016-03-04 17:28:07 -0800413 cas = append(cas, def)
Russ Cox8c195bd2015-02-13 14:40:36 -0500414 }
415
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800416 sw.List.Set(cas)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800417 sw.Nbody.Set(stat)
Russ Cox8c195bd2015-02-13 14:40:36 -0500418 lineno = lno
419}
420
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000421// nSwitchLabel is the number of switch labels generated.
422// This should be per-function, but it is a global counter for now.
423var nSwitchLabel int
Russ Cox8c195bd2015-02-13 14:40:36 -0500424
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000425func newCaseLabel() *Node {
426 label := strconv.Itoa(nSwitchLabel)
427 nSwitchLabel++
428 return newname(Lookup(label))
429}
Russ Cox8c195bd2015-02-13 14:40:36 -0500430
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000431// caseClauses generates a slice of caseClauses
432// corresponding to the clauses in the switch statement sw.
433// Kind is the kind of switch statement.
434func caseClauses(sw *Node, kind int) []*caseClause {
435 var cc []*caseClause
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800436 for _, n := range sw.List.Slice() {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000437 c := new(caseClause)
438 cc = append(cc, c)
439 c.ordinal = len(cc)
Russ Cox8c195bd2015-02-13 14:40:36 -0500440 c.node = n
441
442 if n.Left == nil {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000443 c.typ = caseKindDefault
Russ Cox8c195bd2015-02-13 14:40:36 -0500444 continue
445 }
446
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000447 if kind == switchKindType {
448 // type switch
449 switch {
450 case n.Left.Op == OLITERAL:
451 c.typ = caseKindTypeNil
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700452 case n.Left.Type.IsInterface():
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000453 c.typ = caseKindTypeVar
454 default:
455 c.typ = caseKindTypeConst
456 c.hash = typehash(n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500457 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000458 } else {
459 // expression switch
Russ Cox8c195bd2015-02-13 14:40:36 -0500460 switch consttype(n.Left) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000461 case CTFLT, CTINT, CTRUNE, CTSTR:
462 c.typ = caseKindExprConst
463 default:
464 c.typ = caseKindExprVar
Russ Cox8c195bd2015-02-13 14:40:36 -0500465 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500466 }
467 }
468
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000469 if cc == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500470 return nil
471 }
472
473 // sort by value and diagnose duplicate cases
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000474 if kind == switchKindType {
475 // type switch
476 sort.Sort(caseClauseByType(cc))
477 for i, c1 := range cc {
478 if c1.typ == caseKindTypeNil || c1.typ == caseKindDefault {
479 break
480 }
481 for _, c2 := range cc[i+1:] {
482 if c2.typ == caseKindTypeNil || c2.typ == caseKindDefault || c1.hash != c2.hash {
Russ Cox8c195bd2015-02-13 14:40:36 -0500483 break
484 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000485 if Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800486 yyerrorl(c2.node.Lineno, "duplicate case %v in type switch\n\tprevious case at %v", c2.node.Left.Type, c1.node.Line())
Russ Cox8c195bd2015-02-13 14:40:36 -0500487 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500488 }
489 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000490 } else {
491 // expression switch
492 sort.Sort(caseClauseByExpr(cc))
493 for i, c1 := range cc {
494 if i+1 == len(cc) {
495 break
496 }
497 c2 := cc[i+1]
498 if exprcmp(c1, c2) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500499 continue
500 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000501 setlineno(c2.node)
Russ Cox17228f42015-04-17 12:03:22 -0400502 Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line())
Russ Cox8c195bd2015-02-13 14:40:36 -0500503 }
504 }
505
506 // put list back in processing order
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000507 sort.Sort(caseClauseByOrd(cc))
508 return cc
Russ Cox8c195bd2015-02-13 14:40:36 -0500509}
510
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000511// walk generates an AST that implements sw,
512// where sw is a type switch.
513// The AST is generally of the form of a linear
514// search using if..goto, although binary search
515// is used with long runs of concrete types.
516func (s *typeSwitch) walk(sw *Node) {
Russ Cox66be1482015-05-26 21:30:20 -0400517 cond := sw.Left
518 sw.Left = nil
519
520 if cond == nil {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800521 sw.List.Set(nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500522 return
523 }
Russ Cox66be1482015-05-26 21:30:20 -0400524 if cond.Right == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500525 setlineno(sw)
526 Yyerror("type switch must have an assignment")
527 return
528 }
529
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700530 cond.Right = walkexpr(cond.Right, &sw.Ninit)
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700531 if !cond.Right.Type.IsInterface() {
Russ Cox8c195bd2015-02-13 14:40:36 -0500532 Yyerror("type switch must be on an interface")
533 return
534 }
535
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800536 var cas []*Node
Russ Cox8c195bd2015-02-13 14:40:36 -0500537
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000538 // predeclare temporary variables and the boolean var
Russ Cox66be1482015-05-26 21:30:20 -0400539 s.facename = temp(cond.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500540
Russ Cox66be1482015-05-26 21:30:20 -0400541 a := Nod(OAS, s.facename, cond.Right)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700542 a = typecheck(a, Etop)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800543 cas = append(cas, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500544
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000545 s.okname = temp(Types[TBOOL])
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700546 s.okname = typecheck(s.okname, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -0500547
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000548 s.hashname = temp(Types[TUINT32])
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700549 s.hashname = typecheck(s.hashname, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -0500550
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000551 // set up labels and jumps
552 casebody(sw, s.facename)
Russ Cox8c195bd2015-02-13 14:40:36 -0500553
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000554 cc := caseClauses(sw, switchKindType)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800555 sw.List.Set(nil)
Russ Cox382b44e2015-02-23 16:07:24 -0500556 var def *Node
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000557 if len(cc) > 0 && cc[0].typ == caseKindDefault {
558 def = cc[0].node.Right
559 cc = cc[1:]
Russ Cox8c195bd2015-02-13 14:40:36 -0500560 } else {
561 def = Nod(OBREAK, nil, nil)
562 }
Keith Randalld0c11572016-02-21 20:43:14 -0800563 var typenil *Node
564 if len(cc) > 0 && cc[0].typ == caseKindTypeNil {
565 typenil = cc[0].node.Right
566 cc = cc[1:]
567 }
568
569 // For empty interfaces, do:
570 // if e._type == nil {
571 // do nil case if it exists, otherwise default
572 // }
573 // h := e._type.hash
574 // Use a similar strategy for non-empty interfaces.
575
576 // Get interface descriptor word.
577 typ := Nod(OITAB, s.facename, nil)
578
579 // Check for nil first.
580 i := Nod(OIF, nil, nil)
581 i.Left = Nod(OEQ, typ, nodnil())
582 if typenil != nil {
583 // Do explicit nil case right here.
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800584 i.Nbody.Set1(typenil)
Keith Randalld0c11572016-02-21 20:43:14 -0800585 } else {
586 // Jump to default case.
587 lbl := newCaseLabel()
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800588 i.Nbody.Set1(Nod(OGOTO, lbl, nil))
Keith Randalld0c11572016-02-21 20:43:14 -0800589 // Wrap default case with label.
590 blk := Nod(OBLOCK, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800591 blk.List.Set([]*Node{Nod(OLABEL, lbl, nil), def})
Keith Randalld0c11572016-02-21 20:43:14 -0800592 def = blk
593 }
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700594 i.Left = typecheck(i.Left, Erv)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800595 cas = append(cas, i)
Keith Randalld0c11572016-02-21 20:43:14 -0800596
Matthew Dempsky00e5a682016-04-01 13:36:24 -0700597 if !cond.Right.Type.IsEmptyInterface() {
Keith Randalld0c11572016-02-21 20:43:14 -0800598 // Load type from itab.
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -0700599 typ = NodSym(ODOTPTR, typ, nil)
Keith Randalld0c11572016-02-21 20:43:14 -0800600 typ.Type = Ptrto(Types[TUINT8])
601 typ.Typecheck = 1
602 typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
603 typ.Bounded = true // guaranteed not to fault
604 }
605 // Load hash from type.
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -0700606 h := NodSym(ODOTPTR, typ, nil)
Keith Randalld0c11572016-02-21 20:43:14 -0800607 h.Type = Types[TUINT32]
608 h.Typecheck = 1
609 h.Xoffset = int64(2 * Widthptr) // offset of hash in runtime._type
610 h.Bounded = true // guaranteed not to fault
611 a = Nod(OAS, s.hashname, h)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700612 a = typecheck(a, Etop)
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800613 cas = append(cas, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500614
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000615 // insert type equality check into each case block
616 for _, c := range cc {
617 n := c.node
618 switch c.typ {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000619 case caseKindTypeVar, caseKindTypeConst:
620 n.Right = s.typeone(n)
Keith Randalld0c11572016-02-21 20:43:14 -0800621 default:
622 Fatalf("typeSwitch with bad kind: %d", c.typ)
Russ Cox8c195bd2015-02-13 14:40:36 -0500623 }
624 }
625
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000626 // generate list of if statements, binary search for constant sequences
627 for len(cc) > 0 {
628 if cc[0].typ != caseKindTypeConst {
629 n := cc[0].node
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800630 cas = append(cas, n.Right)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000631 cc = cc[1:]
Russ Cox8c195bd2015-02-13 14:40:36 -0500632 continue
633 }
634
635 // identify run of constants
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000636 var run int
637 for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500638 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500639
640 // sort by hash
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000641 sort.Sort(caseClauseByType(cc[:run]))
Russ Cox8c195bd2015-02-13 14:40:36 -0500642
643 // for debugging: linear search
644 if false {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000645 for i := 0; i < run; i++ {
646 n := cc[i].node
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800647 cas = append(cas, n.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500648 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500649 continue
650 }
651
652 // combine adjacent cases with the same hash
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000653 ncase := 0
654 for i := 0; i < run; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500655 ncase++
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800656 hash := []*Node{cc[i].node.Right}
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000657 for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800658 hash = append(hash, cc[j].node.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500659 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000660 cc[i].node.Right = liststmt(hash)
Russ Cox8c195bd2015-02-13 14:40:36 -0500661 }
662
663 // binary search among cases to narrow by hash
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800664 cas = append(cas, s.walkCases(cc[:ncase]))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000665 cc = cc[ncase:]
Russ Cox8c195bd2015-02-13 14:40:36 -0500666 }
667
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000668 // handle default case
Russ Cox8c195bd2015-02-13 14:40:36 -0500669 if nerrors == 0 {
Ian Lance Taylor1d5001a2016-02-27 14:31:33 -0800670 cas = append(cas, def)
671 sw.Nbody.Set(append(cas, sw.Nbody.Slice()...))
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800672 sw.List.Set(nil)
Ian Lance Taylore28a8902016-03-07 22:54:46 -0800673 walkstmtlist(sw.Nbody.Slice())
Russ Cox8c195bd2015-02-13 14:40:36 -0500674 }
675}
676
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000677// typeone generates an AST that jumps to the
678// case body if the variable is of type t.
679func (s *typeSwitch) typeone(t *Node) *Node {
Russ Coxda094f12015-05-27 10:43:53 -0400680 var name *Node
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800681 var init []*Node
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800682 if t.Rlist.Len() == 0 {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000683 name = nblank
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700684 nblank = typecheck(nblank, Erv|Easgn)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000685 } else {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800686 name = t.Rlist.First()
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800687 init = []*Node{Nod(ODCL, name, nil)}
Russ Coxc4092ac2015-07-30 00:46:42 -0400688 a := Nod(OAS, name, nil)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700689 a = typecheck(a, Etop)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800690 init = append(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500691 }
692
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000693 a := Nod(OAS2, nil, nil)
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800694 a.List.Set([]*Node{name, s.okname}) // name, ok =
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000695 b := Nod(ODOTTYPE, s.facename, nil)
696 b.Type = t.Left.Type // interface.(type)
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800697 a.Rlist.Set1(b)
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700698 a = typecheck(a, Etop)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800699 init = append(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500700
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000701 c := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400702 c.Left = s.okname
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800703 c.Nbody.Set1(t.Right) // if ok { goto l }
Russ Cox8c195bd2015-02-13 14:40:36 -0500704
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800705 return liststmt(append(init, c))
Russ Cox8c195bd2015-02-13 14:40:36 -0500706}
707
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000708// walkCases generates an AST implementing the cases in cc.
709func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
710 if len(cc) < binarySearchMin {
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800711 var cas []*Node
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000712 for _, c := range cc {
713 n := c.node
714 if c.typ != caseKindTypeConst {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200715 Fatalf("typeSwitch walkCases")
Russ Cox8c195bd2015-02-13 14:40:36 -0500716 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000717 a := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400718 a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700719 a.Left = typecheck(a.Left, Erv)
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800720 a.Nbody.Set1(n.Right)
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800721 cas = append(cas, a)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000722 }
723 return liststmt(cas)
724 }
725
726 // find the middle and recur
727 half := len(cc) / 2
728 a := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400729 a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
Josh Bleecher Snyder34699bc2016-03-20 08:03:31 -0700730 a.Left = typecheck(a.Left, Erv)
Ian Lance Taylorc63dbd82016-03-10 10:13:42 -0800731 a.Nbody.Set1(s.walkCases(cc[:half]))
732 a.Rlist.Set1(s.walkCases(cc[half:]))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000733 return a
734}
735
736type caseClauseByOrd []*caseClause
737
738func (x caseClauseByOrd) Len() int { return len(x) }
739func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
740func (x caseClauseByOrd) Less(i, j int) bool {
741 c1, c2 := x[i], x[j]
742 switch {
743 // sort default first
744 case c1.typ == caseKindDefault:
745 return true
746 case c2.typ == caseKindDefault:
747 return false
748
749 // sort nil second
750 case c1.typ == caseKindTypeNil:
751 return true
752 case c2.typ == caseKindTypeNil:
753 return false
754 }
755
756 // sort by ordinal
757 return c1.ordinal < c2.ordinal
758}
759
760type caseClauseByExpr []*caseClause
761
762func (x caseClauseByExpr) Len() int { return len(x) }
763func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
764func (x caseClauseByExpr) Less(i, j int) bool {
765 return exprcmp(x[i], x[j]) < 0
766}
767
768func exprcmp(c1, c2 *caseClause) int {
769 // sort non-constants last
770 if c1.typ != caseKindExprConst {
771 return +1
772 }
773 if c2.typ != caseKindExprConst {
774 return -1
775 }
776
777 n1 := c1.node.Left
778 n2 := c2.node.Left
779
780 // sort by type (for switches on interface)
Robert Griesemer53d43cb2015-10-26 16:00:59 -0700781 ct := n1.Val().Ctype()
782 if ct > n2.Val().Ctype() {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000783 return +1
784 }
Robert Griesemer53d43cb2015-10-26 16:00:59 -0700785 if ct < n2.Val().Ctype() {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000786 return -1
787 }
788 if !Eqtype(n1.Type, n2.Type) {
789 if n1.Type.Vargen > n2.Type.Vargen {
790 return +1
791 } else {
792 return -1
Russ Cox8c195bd2015-02-13 14:40:36 -0500793 }
794 }
795
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000796 // sort by constant value to enable binary search
797 switch ct {
798 case CTFLT:
Matthew Dempskyd3253872016-03-20 13:55:42 -0700799 return n1.Val().U.(*Mpflt).Cmp(n2.Val().U.(*Mpflt))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000800 case CTINT, CTRUNE:
Matthew Dempskyd3253872016-03-20 13:55:42 -0700801 return n1.Val().U.(*Mpint).Cmp(n2.Val().U.(*Mpint))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000802 case CTSTR:
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700803 // Sort strings by length and then by value.
804 // It is much cheaper to compare lengths than values,
805 // and all we need here is consistency.
806 // We respect this sorting in exprSwitch.walkCases.
Russ Cox81d58102015-05-27 00:47:05 -0400807 a := n1.Val().U.(string)
808 b := n2.Val().U.(string)
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700809 if len(a) < len(b) {
810 return -1
811 }
812 if len(a) > len(b) {
813 return +1
814 }
Håvard Haugenc73df922015-09-23 23:31:17 +0200815 if a == b {
816 return 0
817 }
818 if a < b {
819 return -1
820 }
821 return +1
Russ Cox8c195bd2015-02-13 14:40:36 -0500822 }
823
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000824 return 0
825}
826
827type caseClauseByType []*caseClause
828
829func (x caseClauseByType) Len() int { return len(x) }
830func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
831func (x caseClauseByType) Less(i, j int) bool {
832 c1, c2 := x[i], x[j]
833 switch {
834 // sort non-constants last
835 case c1.typ != caseKindTypeConst:
836 return false
837 case c2.typ != caseKindTypeConst:
838 return true
839
840 // sort by hash code
841 case c1.hash != c2.hash:
842 return c1.hash < c2.hash
843 }
844
845 // sort by ordinal
846 return c1.ordinal < c2.ordinal
847}