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