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