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