Source file src/pkg/go/types/stmt.go
1
2
3
4
5
6
7 package types
8
9 import (
10 "go/ast"
11 "go/constant"
12 "go/token"
13 "sort"
14 )
15
16 func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt, iota constant.Value) {
17 if trace {
18 check.trace(body.Pos(), "--- %s: %s", name, sig)
19 defer func() {
20 check.trace(body.End(), "--- <end>")
21 }()
22 }
23
24
25 sig.scope.pos = body.Pos()
26 sig.scope.end = body.End()
27
28
29
30 defer func(ctxt context, indent int) {
31 check.context = ctxt
32 check.indent = indent
33 }(check.context, check.indent)
34 check.context = context{
35 decl: decl,
36 scope: sig.scope,
37 iota: iota,
38 sig: sig,
39 }
40 check.indent = 0
41
42 check.stmtList(0, body.List)
43
44 if check.hasLabel {
45 check.labels(body)
46 }
47
48 if sig.results.Len() > 0 && !check.isTerminating(body, "") {
49 check.error(body.Rbrace, "missing return")
50 }
51
52
53
54 check.usage(sig.scope)
55 }
56
57 func (check *Checker) usage(scope *Scope) {
58 var unused []*Var
59 for _, elem := range scope.elems {
60 if v, _ := elem.(*Var); v != nil && !v.used {
61 unused = append(unused, v)
62 }
63 }
64 sort.Slice(unused, func(i, j int) bool {
65 return unused[i].pos < unused[j].pos
66 })
67 for _, v := range unused {
68 check.softErrorf(v.pos, "%s declared but not used", v.name)
69 }
70
71 for _, scope := range scope.children {
72
73
74 if !scope.isFunc {
75 check.usage(scope)
76 }
77 }
78 }
79
80
81
82
83
84 type stmtContext uint
85
86 const (
87
88 breakOk stmtContext = 1 << iota
89 continueOk
90 fallthroughOk
91
92
93 finalSwitchCase
94 )
95
96 func (check *Checker) simpleStmt(s ast.Stmt) {
97 if s != nil {
98 check.stmt(0, s)
99 }
100 }
101
102 func trimTrailingEmptyStmts(list []ast.Stmt) []ast.Stmt {
103 for i := len(list); i > 0; i-- {
104 if _, ok := list[i-1].(*ast.EmptyStmt); !ok {
105 return list[:i]
106 }
107 }
108 return nil
109 }
110
111 func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
112 ok := ctxt&fallthroughOk != 0
113 inner := ctxt &^ fallthroughOk
114 list = trimTrailingEmptyStmts(list)
115 for i, s := range list {
116 inner := inner
117 if ok && i+1 == len(list) {
118 inner |= fallthroughOk
119 }
120 check.stmt(inner, s)
121 }
122 }
123
124 func (check *Checker) multipleDefaults(list []ast.Stmt) {
125 var first ast.Stmt
126 for _, s := range list {
127 var d ast.Stmt
128 switch c := s.(type) {
129 case *ast.CaseClause:
130 if len(c.List) == 0 {
131 d = s
132 }
133 case *ast.CommClause:
134 if c.Comm == nil {
135 d = s
136 }
137 default:
138 check.invalidAST(s.Pos(), "case/communication clause expected")
139 }
140 if d != nil {
141 if first != nil {
142 check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
143 } else {
144 first = d
145 }
146 }
147 }
148 }
149
150 func (check *Checker) openScope(s ast.Stmt, comment string) {
151 scope := NewScope(check.scope, s.Pos(), s.End(), comment)
152 check.recordScope(s, scope)
153 check.scope = scope
154 }
155
156 func (check *Checker) closeScope() {
157 check.scope = check.scope.Parent()
158 }
159
160 func assignOp(op token.Token) token.Token {
161
162 if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
163 return op + (token.ADD - token.ADD_ASSIGN)
164 }
165 return token.ILLEGAL
166 }
167
168 func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
169 var x operand
170 var msg string
171 switch check.rawExpr(&x, call, nil) {
172 case conversion:
173 msg = "requires function call, not conversion"
174 case expression:
175 msg = "discards result of"
176 case statement:
177 return
178 default:
179 unreachable()
180 }
181 check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
182 }
183
184
185 func goVal(val constant.Value) interface{} {
186
187 if val == nil {
188 return nil
189 }
190
191
192
193
194 switch val.Kind() {
195 case constant.Int:
196 if x, ok := constant.Int64Val(val); ok {
197 return x
198 }
199 if x, ok := constant.Uint64Val(val); ok {
200 return x
201 }
202 case constant.Float:
203 if x, ok := constant.Float64Val(val); ok {
204 return x
205 }
206 case constant.String:
207 return constant.StringVal(val)
208 }
209 return nil
210 }
211
212
213
214
215
216
217
218 type (
219 valueMap map[interface{}][]valueType
220 valueType struct {
221 pos token.Pos
222 typ Type
223 }
224 )
225
226 func (check *Checker) caseValues(x *operand, values []ast.Expr, seen valueMap) {
227 L:
228 for _, e := range values {
229 var v operand
230 check.expr(&v, e)
231 if x.mode == invalid || v.mode == invalid {
232 continue L
233 }
234 check.convertUntyped(&v, x.typ)
235 if v.mode == invalid {
236 continue L
237 }
238
239 res := v
240 check.comparison(&res, x, token.EQL)
241 if res.mode == invalid {
242 continue L
243 }
244 if v.mode != constant_ {
245 continue L
246 }
247
248 if val := goVal(v.val); val != nil {
249
250
251 for _, vt := range seen[val] {
252 if Identical(v.typ, vt.typ) {
253 check.errorf(v.pos(), "duplicate case %s in expression switch", &v)
254 check.error(vt.pos, "\tprevious case")
255 continue L
256 }
257 }
258 seen[val] = append(seen[val], valueType{v.pos(), v.typ})
259 }
260 }
261 }
262
263 func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
264 L:
265 for _, e := range types {
266 T = check.typOrNil(e)
267 if T == Typ[Invalid] {
268 continue L
269 }
270
271
272 for t, pos := range seen {
273 if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
274
275 Ts := "nil"
276 if T != nil {
277 Ts = T.String()
278 }
279 check.errorf(e.Pos(), "duplicate case %s in type switch", Ts)
280 check.error(pos, "\tprevious case")
281 continue L
282 }
283 }
284 seen[T] = e.Pos()
285 if T != nil {
286 check.typeAssertion(e.Pos(), x, xtyp, T)
287 }
288 }
289 return
290 }
291
292
293 func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
294
295 if debug {
296 defer func(scope *Scope) {
297
298 if p := recover(); p != nil {
299 panic(p)
300 }
301 assert(scope == check.scope)
302 }(check.scope)
303 }
304
305
306 defer check.processDelayed(len(check.delayed))
307
308 inner := ctxt &^ (fallthroughOk | finalSwitchCase)
309 switch s := s.(type) {
310 case *ast.BadStmt, *ast.EmptyStmt:
311
312
313 case *ast.DeclStmt:
314 check.declStmt(s.Decl)
315
316 case *ast.LabeledStmt:
317 check.hasLabel = true
318 check.stmt(ctxt, s.Stmt)
319
320 case *ast.ExprStmt:
321
322
323
324 var x operand
325 kind := check.rawExpr(&x, s.X, nil)
326 var msg string
327 switch x.mode {
328 default:
329 if kind == statement {
330 return
331 }
332 msg = "is not used"
333 case builtin:
334 msg = "must be called"
335 case typexpr:
336 msg = "is not an expression"
337 }
338 check.errorf(x.pos(), "%s %s", &x, msg)
339
340 case *ast.SendStmt:
341 var ch, x operand
342 check.expr(&ch, s.Chan)
343 check.expr(&x, s.Value)
344 if ch.mode == invalid || x.mode == invalid {
345 return
346 }
347
348 tch, ok := ch.typ.Underlying().(*Chan)
349 if !ok {
350 check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
351 return
352 }
353
354 if tch.dir == RecvOnly {
355 check.invalidOp(s.Arrow, "cannot send to receive-only type %s", tch)
356 return
357 }
358
359 check.assignment(&x, tch.elem, "send")
360
361 case *ast.IncDecStmt:
362 var op token.Token
363 switch s.Tok {
364 case token.INC:
365 op = token.ADD
366 case token.DEC:
367 op = token.SUB
368 default:
369 check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
370 return
371 }
372
373 var x operand
374 check.expr(&x, s.X)
375 if x.mode == invalid {
376 return
377 }
378 if !isNumeric(x.typ) {
379 check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
380 return
381 }
382
383 Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"}
384 check.binary(&x, nil, s.X, Y, op)
385 if x.mode == invalid {
386 return
387 }
388 check.assignVar(s.X, &x)
389
390 case *ast.AssignStmt:
391 switch s.Tok {
392 case token.ASSIGN, token.DEFINE:
393 if len(s.Lhs) == 0 {
394 check.invalidAST(s.Pos(), "missing lhs in assignment")
395 return
396 }
397 if s.Tok == token.DEFINE {
398 check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
399 } else {
400
401 check.assignVars(s.Lhs, s.Rhs)
402 }
403
404 default:
405
406 if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
407 check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
408 return
409 }
410 op := assignOp(s.Tok)
411 if op == token.ILLEGAL {
412 check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
413 return
414 }
415 var x operand
416 check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
417 if x.mode == invalid {
418 return
419 }
420 check.assignVar(s.Lhs[0], &x)
421 }
422
423 case *ast.GoStmt:
424 check.suspendedCall("go", s.Call)
425
426 case *ast.DeferStmt:
427 check.suspendedCall("defer", s.Call)
428
429 case *ast.ReturnStmt:
430 res := check.sig.results
431 if res.Len() > 0 {
432
433
434 if len(s.Results) == 0 && res.vars[0].name != "" {
435
436
437
438 for _, obj := range res.vars {
439 if alt := check.lookup(obj.name); alt != nil && alt != obj {
440 check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
441 check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
442
443 }
444 }
445 } else {
446
447 check.initVars(res.vars, s.Results, s.Return)
448 }
449 } else if len(s.Results) > 0 {
450 check.error(s.Results[0].Pos(), "no result values expected")
451 check.use(s.Results...)
452 }
453
454 case *ast.BranchStmt:
455 if s.Label != nil {
456 check.hasLabel = true
457 return
458 }
459 switch s.Tok {
460 case token.BREAK:
461 if ctxt&breakOk == 0 {
462 check.error(s.Pos(), "break not in for, switch, or select statement")
463 }
464 case token.CONTINUE:
465 if ctxt&continueOk == 0 {
466 check.error(s.Pos(), "continue not in for statement")
467 }
468 case token.FALLTHROUGH:
469 if ctxt&fallthroughOk == 0 {
470 msg := "fallthrough statement out of place"
471 if ctxt&finalSwitchCase != 0 {
472 msg = "cannot fallthrough final case in switch"
473 }
474 check.error(s.Pos(), msg)
475 }
476 default:
477 check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
478 }
479
480 case *ast.BlockStmt:
481 check.openScope(s, "block")
482 defer check.closeScope()
483
484 check.stmtList(inner, s.List)
485
486 case *ast.IfStmt:
487 check.openScope(s, "if")
488 defer check.closeScope()
489
490 check.simpleStmt(s.Init)
491 var x operand
492 check.expr(&x, s.Cond)
493 if x.mode != invalid && !isBoolean(x.typ) {
494 check.error(s.Cond.Pos(), "non-boolean condition in if statement")
495 }
496 check.stmt(inner, s.Body)
497
498
499 switch s.Else.(type) {
500 case nil, *ast.BadStmt:
501
502 case *ast.IfStmt, *ast.BlockStmt:
503 check.stmt(inner, s.Else)
504 default:
505 check.error(s.Else.Pos(), "invalid else branch in if statement")
506 }
507
508 case *ast.SwitchStmt:
509 inner |= breakOk
510 check.openScope(s, "switch")
511 defer check.closeScope()
512
513 check.simpleStmt(s.Init)
514 var x operand
515 if s.Tag != nil {
516 check.expr(&x, s.Tag)
517
518
519 check.assignment(&x, nil, "switch expression")
520 } else {
521
522
523 x.mode = constant_
524 x.typ = Typ[Bool]
525 x.val = constant.MakeBool(true)
526 x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
527 }
528
529 check.multipleDefaults(s.Body.List)
530
531 seen := make(valueMap)
532 for i, c := range s.Body.List {
533 clause, _ := c.(*ast.CaseClause)
534 if clause == nil {
535 check.invalidAST(c.Pos(), "incorrect expression switch case")
536 continue
537 }
538 check.caseValues(&x, clause.List, seen)
539 check.openScope(clause, "case")
540 inner := inner
541 if i+1 < len(s.Body.List) {
542 inner |= fallthroughOk
543 } else {
544 inner |= finalSwitchCase
545 }
546 check.stmtList(inner, clause.Body)
547 check.closeScope()
548 }
549
550 case *ast.TypeSwitchStmt:
551 inner |= breakOk
552 check.openScope(s, "type switch")
553 defer check.closeScope()
554
555 check.simpleStmt(s.Init)
556
557
558
559
560
561
562
563
564
565 var lhs *ast.Ident
566 var rhs ast.Expr
567 switch guard := s.Assign.(type) {
568 case *ast.ExprStmt:
569 rhs = guard.X
570 case *ast.AssignStmt:
571 if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
572 check.invalidAST(s.Pos(), "incorrect form of type switch guard")
573 return
574 }
575
576 lhs, _ = guard.Lhs[0].(*ast.Ident)
577 if lhs == nil {
578 check.invalidAST(s.Pos(), "incorrect form of type switch guard")
579 return
580 }
581
582 if lhs.Name == "_" {
583
584 check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
585 lhs = nil
586 } else {
587 check.recordDef(lhs, nil)
588 }
589
590 rhs = guard.Rhs[0]
591
592 default:
593 check.invalidAST(s.Pos(), "incorrect form of type switch guard")
594 return
595 }
596
597
598 expr, _ := rhs.(*ast.TypeAssertExpr)
599 if expr == nil || expr.Type != nil {
600 check.invalidAST(s.Pos(), "incorrect form of type switch guard")
601 return
602 }
603 var x operand
604 check.expr(&x, expr.X)
605 if x.mode == invalid {
606 return
607 }
608 xtyp, _ := x.typ.Underlying().(*Interface)
609 if xtyp == nil {
610 check.errorf(x.pos(), "%s is not an interface", &x)
611 return
612 }
613
614 check.multipleDefaults(s.Body.List)
615
616 var lhsVars []*Var
617 seen := make(map[Type]token.Pos)
618 for _, s := range s.Body.List {
619 clause, _ := s.(*ast.CaseClause)
620 if clause == nil {
621 check.invalidAST(s.Pos(), "incorrect type switch case")
622 continue
623 }
624
625 T := check.caseTypes(&x, xtyp, clause.List, seen)
626 check.openScope(clause, "case")
627
628 if lhs != nil {
629
630
631
632
633
634 if len(clause.List) != 1 || T == nil {
635 T = x.typ
636 }
637 obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
638 scopePos := clause.Pos() + token.Pos(len("default"))
639 if n := len(clause.List); n > 0 {
640 scopePos = clause.List[n-1].End()
641 }
642 check.declare(check.scope, nil, obj, scopePos)
643 check.recordImplicit(clause, obj)
644
645
646
647 lhsVars = append(lhsVars, obj)
648 }
649 check.stmtList(inner, clause.Body)
650 check.closeScope()
651 }
652
653
654 if lhs != nil {
655 var used bool
656 for _, v := range lhsVars {
657 if v.used {
658 used = true
659 }
660 v.used = true
661 }
662 if !used {
663 check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
664 }
665 }
666
667 case *ast.SelectStmt:
668 inner |= breakOk
669
670 check.multipleDefaults(s.Body.List)
671
672 for _, s := range s.Body.List {
673 clause, _ := s.(*ast.CommClause)
674 if clause == nil {
675 continue
676 }
677
678
679 valid := false
680 var rhs ast.Expr
681 switch s := clause.Comm.(type) {
682 case nil, *ast.SendStmt:
683 valid = true
684 case *ast.AssignStmt:
685 if len(s.Rhs) == 1 {
686 rhs = s.Rhs[0]
687 }
688 case *ast.ExprStmt:
689 rhs = s.X
690 }
691
692
693 if rhs != nil {
694 if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
695 valid = true
696 }
697 }
698
699 if !valid {
700 check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
701 continue
702 }
703
704 check.openScope(s, "case")
705 if clause.Comm != nil {
706 check.stmt(inner, clause.Comm)
707 }
708 check.stmtList(inner, clause.Body)
709 check.closeScope()
710 }
711
712 case *ast.ForStmt:
713 inner |= breakOk | continueOk
714 check.openScope(s, "for")
715 defer check.closeScope()
716
717 check.simpleStmt(s.Init)
718 if s.Cond != nil {
719 var x operand
720 check.expr(&x, s.Cond)
721 if x.mode != invalid && !isBoolean(x.typ) {
722 check.error(s.Cond.Pos(), "non-boolean condition in for statement")
723 }
724 }
725 check.simpleStmt(s.Post)
726
727
728 if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
729 check.softErrorf(s.Pos(), "cannot declare in post statement")
730
731
732
733 check.use(s.Lhs...)
734 }
735 check.stmt(inner, s.Body)
736
737 case *ast.RangeStmt:
738 inner |= breakOk | continueOk
739 check.openScope(s, "for")
740 defer check.closeScope()
741
742
743 var x operand
744 check.expr(&x, s.X)
745
746
747 var key, val Type
748 if x.mode != invalid {
749 switch typ := x.typ.Underlying().(type) {
750 case *Basic:
751 if isString(typ) {
752 key = Typ[Int]
753 val = universeRune
754 }
755 case *Array:
756 key = Typ[Int]
757 val = typ.elem
758 case *Slice:
759 key = Typ[Int]
760 val = typ.elem
761 case *Pointer:
762 if typ, _ := typ.base.Underlying().(*Array); typ != nil {
763 key = Typ[Int]
764 val = typ.elem
765 }
766 case *Map:
767 key = typ.key
768 val = typ.elem
769 case *Chan:
770 key = typ.elem
771 val = Typ[Invalid]
772 if typ.dir == SendOnly {
773 check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
774
775 }
776 if s.Value != nil {
777 check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
778
779 }
780 }
781 }
782
783 if key == nil {
784 check.errorf(x.pos(), "cannot range over %s", &x)
785
786 }
787
788
789
790
791
792 lhs := [2]ast.Expr{s.Key, s.Value}
793 rhs := [2]Type{key, val}
794
795 if s.Tok == token.DEFINE {
796
797
798
799 var vars []*Var
800 for i, lhs := range lhs {
801 if lhs == nil {
802 continue
803 }
804
805
806 var obj *Var
807 if ident, _ := lhs.(*ast.Ident); ident != nil {
808
809 name := ident.Name
810 obj = NewVar(ident.Pos(), check.pkg, name, nil)
811 check.recordDef(ident, obj)
812
813 if name != "_" {
814 vars = append(vars, obj)
815 }
816 } else {
817 check.errorf(lhs.Pos(), "cannot declare %s", lhs)
818 obj = NewVar(lhs.Pos(), check.pkg, "_", nil)
819 }
820
821
822 if typ := rhs[i]; typ != nil {
823 x.mode = value
824 x.expr = lhs
825 x.typ = typ
826 check.initVar(obj, &x, "range clause")
827 } else {
828 obj.typ = Typ[Invalid]
829 obj.used = true
830 }
831 }
832
833
834 if len(vars) > 0 {
835 scopePos := s.X.End()
836 for _, obj := range vars {
837
838
839
840
841 check.declare(check.scope, nil , obj, scopePos)
842 }
843 } else {
844 check.error(s.TokPos, "no new variables on left side of :=")
845 }
846 } else {
847
848 for i, lhs := range lhs {
849 if lhs == nil {
850 continue
851 }
852 if typ := rhs[i]; typ != nil {
853 x.mode = value
854 x.expr = lhs
855 x.typ = typ
856 check.assignVar(lhs, &x)
857 }
858 }
859 }
860
861 check.stmt(inner, s.Body)
862
863 default:
864 check.error(s.Pos(), "invalid statement")
865 }
866 }
867
View as plain text