blob: 9ed30b2a827d5aea00a5cca5fa636b2eafffe0a5 [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 (
8 "cmd/internal/obj"
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +00009 "sort"
10 "strconv"
Russ Cox8c195bd2015-02-13 14:40:36 -050011)
12
13const (
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000014 // expression switch
15 switchKindExpr = iota // switch a {...} or switch 5 {...}
16 switchKindTrue // switch true {...} or switch {...}
17 switchKindFalse // switch false {...}
18
19 // type switch
20 switchKindType // switch a.(type) {...}
Russ Cox8c195bd2015-02-13 14:40:36 -050021)
22
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000023const (
24 caseKindDefault = iota // default:
25
26 // expression switch
27 caseKindExprConst // case 5:
28 caseKindExprVar // case x:
29
30 // type switch
31 caseKindTypeNil // case nil:
32 caseKindTypeConst // case time.Time: (concrete type, has type hash)
33 caseKindTypeVar // case io.Reader: (interface type)
34)
35
36const binarySearchMin = 4 // minimum number of cases for binary search
37
38// An exprSwitch walks an expression switch.
39type exprSwitch struct {
40 exprname *Node // node for the expression being switched on
41 kind int // kind of switch statement (switchKind*)
Russ Cox8c195bd2015-02-13 14:40:36 -050042}
43
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000044// A typeSwitch walks a type switch.
45type typeSwitch struct {
46 hashname *Node // node for the hash of the type of the variable being switched on
47 facename *Node // node for the concrete type of the variable being switched on
48 okname *Node // boolean node used for comma-ok type assertions
49}
Russ Cox8c195bd2015-02-13 14:40:36 -050050
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000051// A caseClause is a single case clause in a switch statement.
52type caseClause struct {
53 node *Node // points at case statement
54 ordinal int // position in switch
55 hash uint32 // hash of a type switch
56 typ uint8 // type of case
57}
Russ Cox8c195bd2015-02-13 14:40:36 -050058
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000059// typecheckswitch typechecks a switch statement.
60func typecheckswitch(n *Node) {
61 lno := int(lineno)
62 typechecklist(n.Ninit, Etop)
Russ Cox8c195bd2015-02-13 14:40:36 -050063
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000064 var nilonly string
65 var top int
66 var t *Type
Russ Cox8c195bd2015-02-13 14:40:36 -050067
Russ Cox66be1482015-05-26 21:30:20 -040068 if n.Left != nil && n.Left.Op == OTYPESW {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000069 // type switch
70 top = Etype
Russ Cox66be1482015-05-26 21:30:20 -040071 typecheck(&n.Left.Right, Erv)
72 t = n.Left.Right.Type
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000073 if t != nil && t.Etype != TINTER {
Russ Cox66be1482015-05-26 21:30:20 -040074 Yyerror("cannot type switch on non-interface value %v", Nconv(n.Left.Right, obj.FmtLong))
Russ Cox8c195bd2015-02-13 14:40:36 -050075 }
Russ Cox8c195bd2015-02-13 14:40:36 -050076 } else {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000077 // expression switch
78 top = Erv
Russ Cox66be1482015-05-26 21:30:20 -040079 if n.Left != nil {
80 typecheck(&n.Left, Erv)
81 defaultlit(&n.Left, nil)
82 t = n.Left.Type
Russ Cox8c195bd2015-02-13 14:40:36 -050083 } else {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000084 t = Types[TBOOL]
85 }
86 if t != nil {
87 var badtype *Type
88 switch {
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +000089 case !okforeq[t.Etype]:
Russ Cox66be1482015-05-26 21:30:20 -040090 Yyerror("cannot switch on %v", Nconv(n.Left, obj.FmtLong))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000091 case t.Etype == TARRAY && !Isfixedarray(t):
92 nilonly = "slice"
93 case t.Etype == TARRAY && Isfixedarray(t) && algtype1(t, nil) == ANOEQ:
Russ Cox66be1482015-05-26 21:30:20 -040094 Yyerror("cannot switch on %v", Nconv(n.Left, obj.FmtLong))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000095 case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ:
Russ Cox66be1482015-05-26 21:30:20 -040096 Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, obj.FmtLong), badtype)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +000097 case t.Etype == TFUNC:
98 nilonly = "func"
99 case t.Etype == TMAP:
100 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
108 var ll *NodeList
109 for l := n.List; l != nil; l = l.Next {
110 ncase := l.N
111 setlineno(n)
112 if ncase.List == nil {
113 // default
114 if def != nil {
115 Yyerror("multiple defaults in switch (first at %v)", def.Line())
116 } else {
117 def = ncase
118 }
119 } else {
120 for ll = ncase.List; ll != nil; ll = ll.Next {
121 setlineno(ll.N)
122 typecheck(&ll.N, Erv|Etype)
123 if ll.N.Type == nil || t == nil {
124 continue
125 }
126 setlineno(ncase)
127 switch top {
128 // expression switch
129 case Erv:
130 defaultlit(&ll.N, t)
131 switch {
132 case ll.N.Op == OTYPE:
Russ Cox17228f42015-04-17 12:03:22 -0400133 Yyerror("type %v is not an expression", ll.N.Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000134 case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0:
Russ Cox66be1482015-05-26 21:30:20 -0400135 if n.Left != nil {
136 Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", ll.N, n.Left, ll.N.Type, t)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000137 } else {
Russ Cox17228f42015-04-17 12:03:22 -0400138 Yyerror("invalid case %v in switch (mismatched types %v and bool)", ll.N, ll.N.Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000139 }
140 case nilonly != "" && !Isconst(ll.N, CTNIL):
Russ Cox66be1482015-05-26 21:30:20 -0400141 Yyerror("invalid case %v in switch (can only compare %s %v to nil)", ll.N, nilonly, n.Left)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000142 }
143
144 // type switch
145 case Etype:
146 var missing, have *Type
147 var ptr int
148 switch {
149 case ll.N.Op == OLITERAL && Istype(ll.N.Type, TNIL):
150 case ll.N.Op != OTYPE && ll.N.Type != nil: // should this be ||?
151 Yyerror("%v is not a type", Nconv(ll.N, obj.FmtLong))
152 // reset to original type
Russ Cox66be1482015-05-26 21:30:20 -0400153 ll.N = n.Left.Right
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000154 case ll.N.Type.Etype != TINTER && t.Etype == TINTER && !implements(ll.N.Type, t, &missing, &have, &ptr):
Dave Cheney89377802015-09-07 10:37:26 +1000155 if have != nil && !missing.Broke && !have.Broke {
Russ Cox66be1482015-05-26 21:30:20 -0400156 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (wrong type for %v method)\n\thave %v%v\n\twant %v%v", Nconv(n.Left.Right, obj.FmtLong), ll.N.Type, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort), missing.Sym, Tconv(missing.Type, obj.FmtShort))
Dave Cheney89377802015-09-07 10:37:26 +1000157 } else if !missing.Broke {
Russ Cox66be1482015-05-26 21:30:20 -0400158 Yyerror("impossible type switch case: %v cannot have dynamic type %v"+" (missing %v method)", Nconv(n.Left.Right, obj.FmtLong), ll.N.Type, missing.Sym)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000159 }
160 }
161 }
162 }
163 }
164
165 if top == Etype && n.Type != nil {
166 ll = ncase.List
Russ Coxda094f12015-05-27 10:43:53 -0400167 if ncase.Rlist != nil {
168 nvar := ncase.Rlist.N
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000169 if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
170 // single entry type switch
Russ Cox3c3019a2015-05-27 00:44:05 -0400171 nvar.Name.Param.Ntype = typenod(ll.N.Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000172 } else {
173 // multiple entry type switch or default
Russ Cox3c3019a2015-05-27 00:44:05 -0400174 nvar.Name.Param.Ntype = typenod(n.Type)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000175 }
176
177 typecheck(&nvar, Erv|Easgn)
Russ Coxda094f12015-05-27 10:43:53 -0400178 ncase.Rlist.N = nvar
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000179 }
180 }
181
182 typechecklist(ncase.Nbody, Etop)
183 }
184
185 lineno = int32(lno)
Russ Cox8c195bd2015-02-13 14:40:36 -0500186}
187
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000188// walkswitch walks a switch statement.
189func walkswitch(sw *Node) {
190 // convert switch {...} to switch true {...}
Russ Cox66be1482015-05-26 21:30:20 -0400191 if sw.Left == nil {
192 sw.Left = Nodbool(true)
193 typecheck(&sw.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000194 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500195
Russ Cox66be1482015-05-26 21:30:20 -0400196 if sw.Left.Op == OTYPESW {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000197 var s typeSwitch
198 s.walk(sw)
199 } else {
200 var s exprSwitch
201 s.walk(sw)
202 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500203}
204
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000205// walk generates an AST implementing sw.
206// sw is an expression switch.
207// The AST is generally of the form of a linear
208// search using if..goto, although binary search
209// is used with long runs of constants.
210func (s *exprSwitch) walk(sw *Node) {
211 casebody(sw, nil)
212
Russ Cox66be1482015-05-26 21:30:20 -0400213 cond := sw.Left
214 sw.Left = nil
215
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000216 s.kind = switchKindExpr
Russ Cox66be1482015-05-26 21:30:20 -0400217 if Isconst(cond, CTBOOL) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000218 s.kind = switchKindTrue
Russ Cox81d58102015-05-27 00:47:05 -0400219 if !cond.Val().U.(bool) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000220 s.kind = switchKindFalse
221 }
222 }
223
Russ Cox66be1482015-05-26 21:30:20 -0400224 walkexpr(&cond, &sw.Ninit)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000225 t := sw.Type
226 if t == nil {
227 return
228 }
229
230 // convert the switch into OIF statements
231 var cas *NodeList
232 if s.kind == switchKindTrue || s.kind == switchKindFalse {
233 s.exprname = Nodbool(s.kind == switchKindTrue)
Russ Cox66be1482015-05-26 21:30:20 -0400234 } else if consttype(cond) >= 0 {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000235 // leave constants to enable dead code elimination (issue 9608)
Russ Cox66be1482015-05-26 21:30:20 -0400236 s.exprname = cond
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000237 } else {
Russ Cox66be1482015-05-26 21:30:20 -0400238 s.exprname = temp(cond.Type)
239 cas = list1(Nod(OAS, s.exprname, cond))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000240 typechecklist(cas, Etop)
241 }
242
243 // enumerate the cases, and lop off the default case
244 cc := caseClauses(sw, s.kind)
Russ Cox66be1482015-05-26 21:30:20 -0400245 sw.List = nil
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000246 var def *Node
247 if len(cc) > 0 && cc[0].typ == caseKindDefault {
248 def = cc[0].node.Right
249 cc = cc[1:]
250 } else {
251 def = Nod(OBREAK, nil, nil)
252 }
253
254 // handle the cases in order
255 for len(cc) > 0 {
256 // deal with expressions one at a time
Josh Bleecher Snyder25da5942015-03-01 07:54:01 +0000257 if !okforcmp[t.Etype] || cc[0].typ != caseKindExprConst {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000258 a := s.walkCases(cc[:1])
259 cas = list(cas, a)
260 cc = cc[1:]
261 continue
262 }
263
264 // do binary search on runs of constants
265 var run int
266 for run = 1; run < len(cc) && cc[run].typ == caseKindExprConst; run++ {
267 }
268
269 // sort and compile constants
270 sort.Sort(caseClauseByExpr(cc[:run]))
271 a := s.walkCases(cc[:run])
272 cas = list(cas, a)
273 cc = cc[run:]
274 }
275
276 // handle default case
277 if nerrors == 0 {
278 cas = list(cas, def)
279 sw.Nbody = concat(cas, sw.Nbody)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000280 walkstmtlist(sw.Nbody)
281 }
282}
283
284// walkCases generates an AST implementing the cases in cc.
285func (s *exprSwitch) walkCases(cc []*caseClause) *Node {
286 if len(cc) < binarySearchMin {
287 // linear search
288 var cas *NodeList
289 for _, c := range cc {
290 n := c.node
291 lno := int(setlineno(n))
292
293 a := Nod(OIF, nil, nil)
294 if (s.kind != switchKindTrue && s.kind != switchKindFalse) || assignop(n.Left.Type, s.exprname.Type, nil) == OCONVIFACE || assignop(s.exprname.Type, n.Left.Type, nil) == OCONVIFACE {
Russ Cox66be1482015-05-26 21:30:20 -0400295 a.Left = Nod(OEQ, s.exprname, n.Left) // if name == val
296 typecheck(&a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000297 } else if s.kind == switchKindTrue {
Russ Cox66be1482015-05-26 21:30:20 -0400298 a.Left = n.Left // if val
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000299 } else {
300 // s.kind == switchKindFalse
Russ Cox66be1482015-05-26 21:30:20 -0400301 a.Left = Nod(ONOT, n.Left, nil) // if !val
302 typecheck(&a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000303 }
304 a.Nbody = list1(n.Right) // goto l
305
306 cas = list(cas, a)
307 lineno = int32(lno)
308 }
309 return liststmt(cas)
310 }
311
312 // find the middle and recur
313 half := len(cc) / 2
314 a := Nod(OIF, nil, nil)
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700315 mid := cc[half-1].node.Left
316 le := Nod(OLE, s.exprname, mid)
317 if Isconst(mid, CTSTR) {
318 // Search by length and then by value; see exprcmp.
319 lenlt := Nod(OLT, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
320 leneq := Nod(OEQ, Nod(OLEN, s.exprname, nil), Nod(OLEN, mid, nil))
Russ Cox66be1482015-05-26 21:30:20 -0400321 a.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700322 } else {
Russ Cox66be1482015-05-26 21:30:20 -0400323 a.Left = le
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700324 }
Russ Cox66be1482015-05-26 21:30:20 -0400325 typecheck(&a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000326 a.Nbody = list1(s.walkCases(cc[:half]))
Russ Coxffef1802015-05-22 01:16:52 -0400327 a.Rlist = list1(s.walkCases(cc[half:]))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000328 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.
Russ Cox8c195bd2015-02-13 14:40:36 -0500334func casebody(sw *Node, typeswvar *Node) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500335 if sw.List == nil {
336 return
337 }
338
Russ Cox382b44e2015-02-23 16:07:24 -0500339 lno := setlineno(sw)
Russ Cox8c195bd2015-02-13 14:40:36 -0500340
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000341 var cas *NodeList // cases
342 var stat *NodeList // statements
343 var def *Node // defaults
Russ Cox382b44e2015-02-23 16:07:24 -0500344 br := Nod(OBREAK, nil, nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500345
Russ Cox382b44e2015-02-23 16:07:24 -0500346 for l := sw.List; l != nil; l = l.Next {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000347 n := l.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500348 setlineno(n)
349 if n.Op != OXCASE {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200350 Fatalf("casebody %v", Oconv(int(n.Op), 0))
Russ Cox8c195bd2015-02-13 14:40:36 -0500351 }
352 n.Op = OCASE
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000353 needvar := count(n.List) != 1 || n.List.N.Op == OLITERAL
Russ Cox8c195bd2015-02-13 14:40:36 -0500354
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000355 jmp := Nod(OGOTO, newCaseLabel(), nil)
Russ Cox8c195bd2015-02-13 14:40:36 -0500356 if n.List == nil {
357 if def != nil {
358 Yyerror("more than one default case")
359 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500360 // reuse original default case
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000361 n.Right = jmp
Russ Cox8c195bd2015-02-13 14:40:36 -0500362 def = n
363 }
364
365 if n.List != nil && n.List.Next == nil {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000366 // one case -- reuse OCASE node
367 n.Left = n.List.N
368 n.Right = jmp
Russ Cox8c195bd2015-02-13 14:40:36 -0500369 n.List = nil
370 cas = list(cas, n)
371 } else {
372 // expand multi-valued cases
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000373 for lc := n.List; lc != nil; lc = lc.Next {
374 cas = list(cas, Nod(OCASE, lc.N, jmp))
Russ Cox8c195bd2015-02-13 14:40:36 -0500375 }
376 }
377
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000378 stat = list(stat, Nod(OLABEL, jmp.Left, nil))
Russ Coxda094f12015-05-27 10:43:53 -0400379 if typeswvar != nil && needvar && n.Rlist != nil {
380 l := list1(Nod(ODCL, n.Rlist.N, nil))
381 l = list(l, Nod(OAS, n.Rlist.N, typeswvar))
Russ Cox8c195bd2015-02-13 14:40:36 -0500382 typechecklist(l, Etop)
383 stat = concat(stat, l)
384 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500385 stat = concat(stat, n.Nbody)
386
387 // botch - shouldn't fall thru declaration
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000388 last := stat.End.N
Russ Cox8c195bd2015-02-13 14:40:36 -0500389 if last.Xoffset == n.Xoffset && last.Op == OXFALL {
390 if typeswvar != nil {
391 setlineno(last)
392 Yyerror("cannot fallthrough in type switch")
393 }
394
395 if l.Next == nil {
396 setlineno(last)
397 Yyerror("cannot fallthrough final case in switch")
398 }
399
400 last.Op = OFALL
401 } else {
402 stat = list(stat, br)
403 }
404 }
405
406 stat = list(stat, br)
407 if def != nil {
408 cas = list(cas, def)
409 }
410
411 sw.List = cas
412 sw.Nbody = stat
413 lineno = lno
414}
415
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000416// nSwitchLabel is the number of switch labels generated.
417// This should be per-function, but it is a global counter for now.
418var nSwitchLabel int
Russ Cox8c195bd2015-02-13 14:40:36 -0500419
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000420func newCaseLabel() *Node {
421 label := strconv.Itoa(nSwitchLabel)
422 nSwitchLabel++
423 return newname(Lookup(label))
424}
Russ Cox8c195bd2015-02-13 14:40:36 -0500425
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000426// caseClauses generates a slice of caseClauses
427// corresponding to the clauses in the switch statement sw.
428// Kind is the kind of switch statement.
429func caseClauses(sw *Node, kind int) []*caseClause {
430 var cc []*caseClause
Russ Cox382b44e2015-02-23 16:07:24 -0500431 for l := sw.List; l != nil; l = l.Next {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000432 n := l.N
433 c := new(caseClause)
434 cc = append(cc, c)
435 c.ordinal = len(cc)
Russ Cox8c195bd2015-02-13 14:40:36 -0500436 c.node = n
437
438 if n.Left == nil {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000439 c.typ = caseKindDefault
Russ Cox8c195bd2015-02-13 14:40:36 -0500440 continue
441 }
442
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000443 if kind == switchKindType {
444 // type switch
445 switch {
446 case n.Left.Op == OLITERAL:
447 c.typ = caseKindTypeNil
448 case Istype(n.Left.Type, TINTER):
449 c.typ = caseKindTypeVar
450 default:
451 c.typ = caseKindTypeConst
452 c.hash = typehash(n.Left.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500453 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000454 } else {
455 // expression switch
Russ Cox8c195bd2015-02-13 14:40:36 -0500456 switch consttype(n.Left) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000457 case CTFLT, CTINT, CTRUNE, CTSTR:
458 c.typ = caseKindExprConst
459 default:
460 c.typ = caseKindExprVar
Russ Cox8c195bd2015-02-13 14:40:36 -0500461 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500462 }
463 }
464
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000465 if cc == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500466 return nil
467 }
468
469 // sort by value and diagnose duplicate cases
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000470 if kind == switchKindType {
471 // type switch
472 sort.Sort(caseClauseByType(cc))
473 for i, c1 := range cc {
474 if c1.typ == caseKindTypeNil || c1.typ == caseKindDefault {
475 break
476 }
477 for _, c2 := range cc[i+1:] {
478 if c2.typ == caseKindTypeNil || c2.typ == caseKindDefault || c1.hash != c2.hash {
Russ Cox8c195bd2015-02-13 14:40:36 -0500479 break
480 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000481 if Eqtype(c1.node.Left.Type, c2.node.Left.Type) {
Russ Cox17228f42015-04-17 12:03:22 -0400482 yyerrorl(int(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 -0500483 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500484 }
485 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000486 } else {
487 // expression switch
488 sort.Sort(caseClauseByExpr(cc))
489 for i, c1 := range cc {
490 if i+1 == len(cc) {
491 break
492 }
493 c2 := cc[i+1]
494 if exprcmp(c1, c2) != 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500495 continue
496 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000497 setlineno(c2.node)
Russ Cox17228f42015-04-17 12:03:22 -0400498 Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line())
Russ Cox8c195bd2015-02-13 14:40:36 -0500499 }
500 }
501
502 // put list back in processing order
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000503 sort.Sort(caseClauseByOrd(cc))
504 return cc
Russ Cox8c195bd2015-02-13 14:40:36 -0500505}
506
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000507// walk generates an AST that implements sw,
508// where sw is a type switch.
509// The AST is generally of the form of a linear
510// search using if..goto, although binary search
511// is used with long runs of concrete types.
512func (s *typeSwitch) walk(sw *Node) {
Russ Cox66be1482015-05-26 21:30:20 -0400513 cond := sw.Left
514 sw.Left = nil
515
516 if cond == nil {
517 sw.List = nil
Russ Cox8c195bd2015-02-13 14:40:36 -0500518 return
519 }
Russ Cox66be1482015-05-26 21:30:20 -0400520 if cond.Right == nil {
Russ Cox8c195bd2015-02-13 14:40:36 -0500521 setlineno(sw)
522 Yyerror("type switch must have an assignment")
523 return
524 }
525
Russ Cox66be1482015-05-26 21:30:20 -0400526 walkexpr(&cond.Right, &sw.Ninit)
527 if !Istype(cond.Right.Type, TINTER) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500528 Yyerror("type switch must be on an interface")
529 return
530 }
531
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000532 var cas *NodeList
Russ Cox8c195bd2015-02-13 14:40:36 -0500533
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000534 // predeclare temporary variables and the boolean var
Russ Cox66be1482015-05-26 21:30:20 -0400535 s.facename = temp(cond.Right.Type)
Russ Cox8c195bd2015-02-13 14:40:36 -0500536
Russ Cox66be1482015-05-26 21:30:20 -0400537 a := Nod(OAS, s.facename, cond.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500538 typecheck(&a, Etop)
539 cas = list(cas, a)
540
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000541 s.okname = temp(Types[TBOOL])
542 typecheck(&s.okname, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -0500543
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000544 s.hashname = temp(Types[TUINT32])
545 typecheck(&s.hashname, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -0500546
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000547 // set up labels and jumps
548 casebody(sw, s.facename)
Russ Cox8c195bd2015-02-13 14:40:36 -0500549
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000550 // calculate type hash
Russ Cox66be1482015-05-26 21:30:20 -0400551 t := cond.Right.Type
Russ Coxdc7b54b2015-02-17 22:13:49 -0500552 if isnilinter(t) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500553 a = syslook("efacethash", 1)
554 } else {
555 a = syslook("ifacethash", 1)
556 }
Russ Cox13f9c8b2015-03-08 13:33:49 -0400557 substArgTypes(a, t)
Russ Cox8c195bd2015-02-13 14:40:36 -0500558 a = Nod(OCALL, a, nil)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000559 a.List = list1(s.facename)
560 a = Nod(OAS, s.hashname, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500561 typecheck(&a, Etop)
562 cas = list(cas, a)
563
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000564 cc := caseClauses(sw, switchKindType)
Russ Cox66be1482015-05-26 21:30:20 -0400565 sw.List = nil
Russ Cox382b44e2015-02-23 16:07:24 -0500566 var def *Node
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000567 if len(cc) > 0 && cc[0].typ == caseKindDefault {
568 def = cc[0].node.Right
569 cc = cc[1:]
Russ Cox8c195bd2015-02-13 14:40:36 -0500570 } else {
571 def = Nod(OBREAK, nil, nil)
572 }
573
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000574 // insert type equality check into each case block
575 for _, c := range cc {
576 n := c.node
577 switch c.typ {
578 case caseKindTypeNil:
579 var v Val
Russ Cox71080fb2015-05-26 22:50:45 -0400580 v.U = new(NilVal)
Russ Cox8c195bd2015-02-13 14:40:36 -0500581 a = Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400582 a.Left = Nod(OEQ, s.facename, nodlit(v))
583 typecheck(&a.Left, Erv)
Russ Cox8c195bd2015-02-13 14:40:36 -0500584 a.Nbody = list1(n.Right) // if i==nil { goto l }
585 n.Right = a
586
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000587 case caseKindTypeVar, caseKindTypeConst:
588 n.Right = s.typeone(n)
Russ Cox8c195bd2015-02-13 14:40:36 -0500589 }
590 }
591
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000592 // generate list of if statements, binary search for constant sequences
593 for len(cc) > 0 {
594 if cc[0].typ != caseKindTypeConst {
595 n := cc[0].node
Russ Cox8c195bd2015-02-13 14:40:36 -0500596 cas = list(cas, n.Right)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000597 cc = cc[1:]
Russ Cox8c195bd2015-02-13 14:40:36 -0500598 continue
599 }
600
601 // identify run of constants
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000602 var run int
603 for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500604 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500605
606 // sort by hash
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000607 sort.Sort(caseClauseByType(cc[:run]))
Russ Cox8c195bd2015-02-13 14:40:36 -0500608
609 // for debugging: linear search
610 if false {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000611 for i := 0; i < run; i++ {
612 n := cc[i].node
Russ Cox8c195bd2015-02-13 14:40:36 -0500613 cas = list(cas, n.Right)
614 }
Russ Cox8c195bd2015-02-13 14:40:36 -0500615 continue
616 }
617
618 // combine adjacent cases with the same hash
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000619 ncase := 0
620 for i := 0; i < run; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500621 ncase++
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000622 hash := list1(cc[i].node.Right)
623 for j := i + 1; j < run && cc[i].hash == cc[j].hash; j++ {
624 hash = list(hash, cc[j].node.Right)
Russ Cox8c195bd2015-02-13 14:40:36 -0500625 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000626 cc[i].node.Right = liststmt(hash)
Russ Cox8c195bd2015-02-13 14:40:36 -0500627 }
628
629 // binary search among cases to narrow by hash
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000630 cas = list(cas, s.walkCases(cc[:ncase]))
631 cc = cc[ncase:]
Russ Cox8c195bd2015-02-13 14:40:36 -0500632 }
633
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000634 // handle default case
Russ Cox8c195bd2015-02-13 14:40:36 -0500635 if nerrors == 0 {
636 cas = list(cas, def)
637 sw.Nbody = concat(cas, sw.Nbody)
638 sw.List = nil
639 walkstmtlist(sw.Nbody)
640 }
641}
642
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000643// typeone generates an AST that jumps to the
644// case body if the variable is of type t.
645func (s *typeSwitch) typeone(t *Node) *Node {
Russ Coxda094f12015-05-27 10:43:53 -0400646 var name *Node
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000647 var init *NodeList
Russ Coxda094f12015-05-27 10:43:53 -0400648 if t.Rlist == nil {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000649 name = nblank
Russ Coxda094f12015-05-27 10:43:53 -0400650 typecheck(&nblank, Erv|Easgn)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000651 } else {
Russ Coxda094f12015-05-27 10:43:53 -0400652 name = t.Rlist.N
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000653 init = list1(Nod(ODCL, name, nil))
Russ Coxc4092ac2015-07-30 00:46:42 -0400654 a := Nod(OAS, name, nil)
655 typecheck(&a, Etop)
656 init = list(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500657 }
658
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000659 a := Nod(OAS2, nil, nil)
660 a.List = list(list1(name), s.okname) // name, ok =
661 b := Nod(ODOTTYPE, s.facename, nil)
662 b.Type = t.Left.Type // interface.(type)
663 a.Rlist = list1(b)
664 typecheck(&a, Etop)
665 init = list(init, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500666
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000667 c := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400668 c.Left = s.okname
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000669 c.Nbody = list1(t.Right) // if ok { goto l }
Russ Cox8c195bd2015-02-13 14:40:36 -0500670
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000671 return liststmt(list(init, c))
Russ Cox8c195bd2015-02-13 14:40:36 -0500672}
673
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000674// walkCases generates an AST implementing the cases in cc.
675func (s *typeSwitch) walkCases(cc []*caseClause) *Node {
676 if len(cc) < binarySearchMin {
677 var cas *NodeList
678 for _, c := range cc {
679 n := c.node
680 if c.typ != caseKindTypeConst {
Håvard Haugen3c9fa382015-08-30 23:10:03 +0200681 Fatalf("typeSwitch walkCases")
Russ Cox8c195bd2015-02-13 14:40:36 -0500682 }
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000683 a := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400684 a.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
685 typecheck(&a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000686 a.Nbody = list1(n.Right)
687 cas = list(cas, a)
688 }
689 return liststmt(cas)
690 }
691
692 // find the middle and recur
693 half := len(cc) / 2
694 a := Nod(OIF, nil, nil)
Russ Cox66be1482015-05-26 21:30:20 -0400695 a.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
696 typecheck(&a.Left, Erv)
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000697 a.Nbody = list1(s.walkCases(cc[:half]))
Russ Coxffef1802015-05-22 01:16:52 -0400698 a.Rlist = list1(s.walkCases(cc[half:]))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000699 return a
700}
701
702type caseClauseByOrd []*caseClause
703
704func (x caseClauseByOrd) Len() int { return len(x) }
705func (x caseClauseByOrd) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
706func (x caseClauseByOrd) Less(i, j int) bool {
707 c1, c2 := x[i], x[j]
708 switch {
709 // sort default first
710 case c1.typ == caseKindDefault:
711 return true
712 case c2.typ == caseKindDefault:
713 return false
714
715 // sort nil second
716 case c1.typ == caseKindTypeNil:
717 return true
718 case c2.typ == caseKindTypeNil:
719 return false
720 }
721
722 // sort by ordinal
723 return c1.ordinal < c2.ordinal
724}
725
726type caseClauseByExpr []*caseClause
727
728func (x caseClauseByExpr) Len() int { return len(x) }
729func (x caseClauseByExpr) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
730func (x caseClauseByExpr) Less(i, j int) bool {
731 return exprcmp(x[i], x[j]) < 0
732}
733
734func exprcmp(c1, c2 *caseClause) int {
735 // sort non-constants last
736 if c1.typ != caseKindExprConst {
737 return +1
738 }
739 if c2.typ != caseKindExprConst {
740 return -1
741 }
742
743 n1 := c1.node.Left
744 n2 := c2.node.Left
745
746 // sort by type (for switches on interface)
Russ Cox81d58102015-05-27 00:47:05 -0400747 ct := int(n1.Val().Ctype())
748 if ct > int(n2.Val().Ctype()) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000749 return +1
750 }
Russ Cox81d58102015-05-27 00:47:05 -0400751 if ct < int(n2.Val().Ctype()) {
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000752 return -1
753 }
754 if !Eqtype(n1.Type, n2.Type) {
755 if n1.Type.Vargen > n2.Type.Vargen {
756 return +1
757 } else {
758 return -1
Russ Cox8c195bd2015-02-13 14:40:36 -0500759 }
760 }
761
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000762 // sort by constant value to enable binary search
763 switch ct {
764 case CTFLT:
Russ Cox81d58102015-05-27 00:47:05 -0400765 return mpcmpfltflt(n1.Val().U.(*Mpflt), n2.Val().U.(*Mpflt))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000766 case CTINT, CTRUNE:
Russ Cox81d58102015-05-27 00:47:05 -0400767 return Mpcmpfixfix(n1.Val().U.(*Mpint), n2.Val().U.(*Mpint))
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000768 case CTSTR:
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700769 // Sort strings by length and then by value.
770 // It is much cheaper to compare lengths than values,
771 // and all we need here is consistency.
772 // We respect this sorting in exprSwitch.walkCases.
Russ Cox81d58102015-05-27 00:47:05 -0400773 a := n1.Val().U.(string)
774 b := n2.Val().U.(string)
Josh Bleecher Snyder4bc9bad2015-03-17 16:10:31 -0700775 if len(a) < len(b) {
776 return -1
777 }
778 if len(a) > len(b) {
779 return +1
780 }
Håvard Haugenc73df922015-09-23 23:31:17 +0200781 if a == b {
782 return 0
783 }
784 if a < b {
785 return -1
786 }
787 return +1
Russ Cox8c195bd2015-02-13 14:40:36 -0500788 }
789
Josh Bleecher Snyder85c6f712015-02-27 20:44:45 +0000790 return 0
791}
792
793type caseClauseByType []*caseClause
794
795func (x caseClauseByType) Len() int { return len(x) }
796func (x caseClauseByType) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
797func (x caseClauseByType) Less(i, j int) bool {
798 c1, c2 := x[i], x[j]
799 switch {
800 // sort non-constants last
801 case c1.typ != caseKindTypeConst:
802 return false
803 case c2.typ != caseKindTypeConst:
804 return true
805
806 // sort by hash code
807 case c1.hash != c2.hash:
808 return c1.hash < c2.hash
809 }
810
811 // sort by ordinal
812 return c1.ordinal < c2.ordinal
813}