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, "%s declared and 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 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 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 check.errorf(&v, DuplicateCase, "duplicate case %s in expression switch", &v)
261 check.error(atPos(vt.pos), DuplicateCase, "\tprevious case")
262 continue L
263 }
264 }
265 seen[val] = append(seen[val], valueType{v.Pos(), v.typ})
266 }
267 }
268 }
269
270
271 func (check *Checker) isNil(e ast.Expr) bool {
272
273 if name, _ := unparen(e).(*ast.Ident); name != nil {
274 _, ok := check.lookup(name.Name).(*Nil)
275 return ok
276 }
277 return false
278 }
279
280
281 func (check *Checker) caseTypes(x *operand, types []ast.Expr, seen map[Type]ast.Expr) (T Type) {
282 var dummy operand
283 L:
284 for _, e := range types {
285
286 if check.isNil(e) {
287 T = nil
288 check.expr(nil, &dummy, e)
289 } else {
290 T = check.varType(e)
291 if !isValid(T) {
292 continue L
293 }
294 }
295
296
297 for t, other := range seen {
298 if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
299
300 Ts := "nil"
301 if T != nil {
302 Ts = TypeString(T, check.qualifier)
303 }
304 check.errorf(e, DuplicateCase, "duplicate case %s in type switch", Ts)
305 check.error(other, DuplicateCase, "\tprevious case")
306 continue L
307 }
308 }
309 seen[T] = e
310 if x != nil && T != nil {
311 check.typeAssertion(e, x, T, true)
312 }
313 }
314 return
315 }
316
317
318
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 func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
361
362 if debug {
363 defer func(scope *Scope) {
364
365 if p := recover(); p != nil {
366 panic(p)
367 }
368 assert(scope == check.scope)
369 }(check.scope)
370 }
371
372
373 defer check.processDelayed(len(check.delayed))
374
375
376 inner := ctxt &^ (fallthroughOk | finalSwitchCase | inTypeSwitch)
377
378 switch s := s.(type) {
379 case *ast.BadStmt, *ast.EmptyStmt:
380
381
382 case *ast.DeclStmt:
383 check.declStmt(s.Decl)
384
385 case *ast.LabeledStmt:
386 check.hasLabel = true
387 check.stmt(ctxt, s.Stmt)
388
389 case *ast.ExprStmt:
390
391
392
393 var x operand
394 kind := check.rawExpr(nil, &x, s.X, nil, false)
395 var msg string
396 var code Code
397 switch x.mode {
398 default:
399 if kind == statement {
400 return
401 }
402 msg = "is not used"
403 code = UnusedExpr
404 case builtin:
405 msg = "must be called"
406 code = UncalledBuiltin
407 case typexpr:
408 msg = "is not an expression"
409 code = NotAnExpr
410 }
411 check.errorf(&x, code, "%s %s", &x, msg)
412
413 case *ast.SendStmt:
414 var ch, val operand
415 check.expr(nil, &ch, s.Chan)
416 check.expr(nil, &val, s.Value)
417 if ch.mode == invalid || val.mode == invalid {
418 return
419 }
420 u := coreType(ch.typ)
421 if u == nil {
422 check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to %s: no core type", &ch)
423 return
424 }
425 uch, _ := u.(*Chan)
426 if uch == nil {
427 check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to non-channel %s", &ch)
428 return
429 }
430 if uch.dir == RecvOnly {
431 check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch)
432 return
433 }
434 check.assignment(&val, uch.elem, "send")
435
436 case *ast.IncDecStmt:
437 var op token.Token
438 switch s.Tok {
439 case token.INC:
440 op = token.ADD
441 case token.DEC:
442 op = token.SUB
443 default:
444 check.errorf(inNode(s, s.TokPos), InvalidSyntaxTree, "unknown inc/dec operation %s", s.Tok)
445 return
446 }
447
448 var x operand
449 check.expr(nil, &x, s.X)
450 if x.mode == invalid {
451 return
452 }
453 if !allNumeric(x.typ) {
454 check.errorf(s.X, NonNumericIncDec, invalidOp+"%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
455 return
456 }
457
458 Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"}
459 check.binary(&x, nil, s.X, Y, op, s.TokPos)
460 if x.mode == invalid {
461 return
462 }
463 check.assignVar(s.X, nil, &x, "assignment")
464
465 case *ast.AssignStmt:
466 switch s.Tok {
467 case token.ASSIGN, token.DEFINE:
468 if len(s.Lhs) == 0 {
469 check.error(s, InvalidSyntaxTree, "missing lhs in assignment")
470 return
471 }
472 if s.Tok == token.DEFINE {
473 check.shortVarDecl(inNode(s, s.TokPos), s.Lhs, s.Rhs)
474 } else {
475
476 check.assignVars(s.Lhs, s.Rhs)
477 }
478
479 default:
480
481 if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
482 check.errorf(inNode(s, s.TokPos), MultiValAssignOp, "assignment operation %s requires single-valued expressions", s.Tok)
483 return
484 }
485 op := assignOp(s.Tok)
486 if op == token.ILLEGAL {
487 check.errorf(atPos(s.TokPos), InvalidSyntaxTree, "unknown assignment operation %s", s.Tok)
488 return
489 }
490 var x operand
491 check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op, s.TokPos)
492 if x.mode == invalid {
493 return
494 }
495 check.assignVar(s.Lhs[0], nil, &x, "assignment")
496 }
497
498 case *ast.GoStmt:
499 check.suspendedCall("go", s.Call)
500
501 case *ast.DeferStmt:
502 check.suspendedCall("defer", s.Call)
503
504 case *ast.ReturnStmt:
505 res := check.sig.results
506
507
508 if len(s.Results) == 0 && res.Len() > 0 && res.vars[0].name != "" {
509
510
511
512 for _, obj := range res.vars {
513 if alt := check.lookup(obj.name); alt != nil && alt != obj {
514 check.errorf(s, OutOfScopeResult, "result parameter %s not in scope at return", obj.name)
515 check.errorf(alt, OutOfScopeResult, "\tinner declaration of %s", obj)
516
517 }
518 }
519 } else {
520 var lhs []*Var
521 if res.Len() > 0 {
522 lhs = res.vars
523 }
524 check.initVars(lhs, s.Results, s)
525 }
526
527 case *ast.BranchStmt:
528 if s.Label != nil {
529 check.hasLabel = true
530 return
531 }
532 switch s.Tok {
533 case token.BREAK:
534 if ctxt&breakOk == 0 {
535 check.error(s, MisplacedBreak, "break not in for, switch, or select statement")
536 }
537 case token.CONTINUE:
538 if ctxt&continueOk == 0 {
539 check.error(s, MisplacedContinue, "continue not in for statement")
540 }
541 case token.FALLTHROUGH:
542 if ctxt&fallthroughOk == 0 {
543 var msg string
544 switch {
545 case ctxt&finalSwitchCase != 0:
546 msg = "cannot fallthrough final case in switch"
547 case ctxt&inTypeSwitch != 0:
548 msg = "cannot fallthrough in type switch"
549 default:
550 msg = "fallthrough statement out of place"
551 }
552 check.error(s, MisplacedFallthrough, msg)
553 }
554 default:
555 check.errorf(s, InvalidSyntaxTree, "branch statement: %s", s.Tok)
556 }
557
558 case *ast.BlockStmt:
559 check.openScope(s, "block")
560 defer check.closeScope()
561
562 check.stmtList(inner, s.List)
563
564 case *ast.IfStmt:
565 check.openScope(s, "if")
566 defer check.closeScope()
567
568 check.simpleStmt(s.Init)
569 var x operand
570 check.expr(nil, &x, s.Cond)
571 if x.mode != invalid && !allBoolean(x.typ) {
572 check.error(s.Cond, InvalidCond, "non-boolean condition in if statement")
573 }
574 check.stmt(inner, s.Body)
575
576
577 switch s.Else.(type) {
578 case nil, *ast.BadStmt:
579
580 case *ast.IfStmt, *ast.BlockStmt:
581 check.stmt(inner, s.Else)
582 default:
583 check.error(s.Else, InvalidSyntaxTree, "invalid else branch in if statement")
584 }
585
586 case *ast.SwitchStmt:
587 inner |= breakOk
588 check.openScope(s, "switch")
589 defer check.closeScope()
590
591 check.simpleStmt(s.Init)
592 var x operand
593 if s.Tag != nil {
594 check.expr(nil, &x, s.Tag)
595
596
597 check.assignment(&x, nil, "switch expression")
598 if x.mode != invalid && !Comparable(x.typ) && !hasNil(x.typ) {
599 check.errorf(&x, InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ)
600 x.mode = invalid
601 }
602 } else {
603
604
605 x.mode = constant_
606 x.typ = Typ[Bool]
607 x.val = constant.MakeBool(true)
608 x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
609 }
610
611 check.multipleDefaults(s.Body.List)
612
613 seen := make(valueMap)
614 for i, c := range s.Body.List {
615 clause, _ := c.(*ast.CaseClause)
616 if clause == nil {
617 check.error(c, InvalidSyntaxTree, "incorrect expression switch case")
618 continue
619 }
620 check.caseValues(&x, clause.List, seen)
621 check.openScope(clause, "case")
622 inner := inner
623 if i+1 < len(s.Body.List) {
624 inner |= fallthroughOk
625 } else {
626 inner |= finalSwitchCase
627 }
628 check.stmtList(inner, clause.Body)
629 check.closeScope()
630 }
631
632 case *ast.TypeSwitchStmt:
633 inner |= breakOk | inTypeSwitch
634 check.openScope(s, "type switch")
635 defer check.closeScope()
636
637 check.simpleStmt(s.Init)
638
639
640
641
642
643
644
645
646
647 var lhs *ast.Ident
648 var rhs ast.Expr
649 switch guard := s.Assign.(type) {
650 case *ast.ExprStmt:
651 rhs = guard.X
652 case *ast.AssignStmt:
653 if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
654 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
655 return
656 }
657
658 lhs, _ = guard.Lhs[0].(*ast.Ident)
659 if lhs == nil {
660 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
661 return
662 }
663
664 if lhs.Name == "_" {
665
666 check.softErrorf(lhs, NoNewVar, "no new variable on left side of :=")
667 lhs = nil
668 } else {
669 check.recordDef(lhs, nil)
670 }
671
672 rhs = guard.Rhs[0]
673
674 default:
675 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
676 return
677 }
678
679
680 expr, _ := rhs.(*ast.TypeAssertExpr)
681 if expr == nil || expr.Type != nil {
682 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
683 return
684 }
685 var x operand
686 check.expr(nil, &x, expr.X)
687 if x.mode == invalid {
688 return
689 }
690
691 var sx *operand
692 if isTypeParam(x.typ) {
693 check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x)
694 } else {
695 if _, ok := under(x.typ).(*Interface); ok {
696 sx = &x
697 } else {
698 check.errorf(&x, InvalidTypeSwitch, "%s is not an interface", &x)
699 }
700 }
701
702 check.multipleDefaults(s.Body.List)
703
704 var lhsVars []*Var
705 seen := make(map[Type]ast.Expr)
706 for _, s := range s.Body.List {
707 clause, _ := s.(*ast.CaseClause)
708 if clause == nil {
709 check.error(s, InvalidSyntaxTree, "incorrect type switch case")
710 continue
711 }
712
713 T := check.caseTypes(sx, clause.List, seen)
714 check.openScope(clause, "case")
715
716 if lhs != nil {
717
718
719
720
721
722 if len(clause.List) != 1 || T == nil {
723 T = x.typ
724 }
725 obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
726 scopePos := clause.Pos() + token.Pos(len("default"))
727 if n := len(clause.List); n > 0 {
728 scopePos = clause.List[n-1].End()
729 }
730 check.declare(check.scope, nil, obj, scopePos)
731 check.recordImplicit(clause, obj)
732
733
734
735 lhsVars = append(lhsVars, obj)
736 }
737 check.stmtList(inner, clause.Body)
738 check.closeScope()
739 }
740
741
742 if lhs != nil {
743 var used bool
744 for _, v := range lhsVars {
745 if v.used {
746 used = true
747 }
748 v.used = true
749 }
750 if !used {
751 check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Name)
752 }
753 }
754
755 case *ast.SelectStmt:
756 inner |= breakOk
757
758 check.multipleDefaults(s.Body.List)
759
760 for _, s := range s.Body.List {
761 clause, _ := s.(*ast.CommClause)
762 if clause == nil {
763 continue
764 }
765
766
767 valid := false
768 var rhs ast.Expr
769 switch s := clause.Comm.(type) {
770 case nil, *ast.SendStmt:
771 valid = true
772 case *ast.AssignStmt:
773 if len(s.Rhs) == 1 {
774 rhs = s.Rhs[0]
775 }
776 case *ast.ExprStmt:
777 rhs = s.X
778 }
779
780
781 if rhs != nil {
782 if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
783 valid = true
784 }
785 }
786
787 if !valid {
788 check.error(clause.Comm, InvalidSelectCase, "select case must be send or receive (possibly with assignment)")
789 continue
790 }
791
792 check.openScope(s, "case")
793 if clause.Comm != nil {
794 check.stmt(inner, clause.Comm)
795 }
796 check.stmtList(inner, clause.Body)
797 check.closeScope()
798 }
799
800 case *ast.ForStmt:
801 inner |= breakOk | continueOk
802 check.openScope(s, "for")
803 defer check.closeScope()
804
805 check.simpleStmt(s.Init)
806 if s.Cond != nil {
807 var x operand
808 check.expr(nil, &x, s.Cond)
809 if x.mode != invalid && !allBoolean(x.typ) {
810 check.error(s.Cond, InvalidCond, "non-boolean condition in for statement")
811 }
812 }
813 check.simpleStmt(s.Post)
814
815
816 if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
817 check.softErrorf(s, InvalidPostDecl, "cannot declare in post statement")
818
819
820
821 check.use(s.Lhs...)
822 }
823 check.stmt(inner, s.Body)
824
825 case *ast.RangeStmt:
826 inner |= breakOk | continueOk
827 check.rangeStmt(inner, s)
828
829 default:
830 check.error(s, InvalidSyntaxTree, "invalid statement")
831 }
832 }
833
834 func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
835
836 type Expr = ast.Expr
837 type identType = ast.Ident
838 identName := func(n *identType) string { return n.Name }
839 sKey, sValue := s.Key, s.Value
840 var sExtra ast.Expr = nil
841 isDef := s.Tok == token.DEFINE
842 rangeVar := s.X
843 noNewVarPos := inNode(s, s.TokPos)
844
845
846
847
848 var x operand
849 check.expr(nil, &x, rangeVar)
850
851
852 var key, val Type
853 if x.mode != invalid {
854
855 k, v, cause, isFunc, ok := rangeKeyVal(x.typ, func(v goVersion) bool {
856 return check.allowVersion(check.pkg, x.expr, v)
857 })
858 switch {
859 case !ok && cause != "":
860 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s: %s", &x, cause)
861 case !ok:
862 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s", &x)
863 case k == nil && sKey != nil:
864 check.softErrorf(sKey, InvalidIterVar, "range over %s permits no iteration variables", &x)
865 case v == nil && sValue != nil:
866 check.softErrorf(sValue, InvalidIterVar, "range over %s permits only one iteration variable", &x)
867 case sExtra != nil:
868 check.softErrorf(sExtra, InvalidIterVar, "range clause permits at most two iteration variables")
869 case isFunc && ((k == nil) != (sKey == nil) || (v == nil) != (sValue == nil)):
870 var count string
871 switch {
872 case k == nil:
873 count = "no iteration variables"
874 case v == nil:
875 count = "one iteration variable"
876 default:
877 count = "two iteration variables"
878 }
879 check.softErrorf(&x, InvalidIterVar, "range over %s must have %s", &x, count)
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 constIntRange := x.mode == constant_ && 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
922
923 if constIntRange {
924 check.initVar(obj, &x, "range clause")
925 } else if typ := rhs[i]; typ != nil {
926 x.mode = value
927 x.expr = lhs
928 x.typ = typ
929 check.initVar(obj, &x, "assignment")
930 } else {
931 obj.typ = Typ[Invalid]
932 obj.used = true
933 }
934 }
935
936
937 if len(vars) > 0 {
938 scopePos := s.Body.Pos()
939 for _, obj := range vars {
940 check.declare(check.scope, nil , obj, scopePos)
941 }
942 } else {
943 check.error(noNewVarPos, NoNewVar, "no new variables on left side of :=")
944 }
945 } else if sKey != nil {
946
947 for i, lhs := range lhs {
948 if lhs == nil {
949 continue
950 }
951
952 if constIntRange {
953 check.assignVar(lhs, nil, &x, "range clause")
954 } else if typ := rhs[i]; typ != nil {
955 x.mode = value
956 x.expr = lhs
957 x.typ = typ
958 check.assignVar(lhs, nil, &x, "assignment")
959 }
960 }
961 } else if constIntRange {
962
963
964
965
966
967 check.assignment(&x, nil, "range clause")
968 }
969
970 check.stmt(inner, s.Body)
971 }
972
973
974
975
976
977
978 func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, cause string, isFunc, ok bool) {
979 bad := func(cause string) (Type, Type, string, bool, bool) {
980 return Typ[Invalid], Typ[Invalid], cause, false, false
981 }
982 toSig := func(t Type) *Signature {
983 sig, _ := coreType(t).(*Signature)
984 return sig
985 }
986
987 orig := typ
988 switch typ := arrayPtrDeref(coreType(typ)).(type) {
989 case nil:
990 return bad("no core type")
991 case *Basic:
992 if isString(typ) {
993 return Typ[Int], universeRune, "", false, true
994 }
995 if isInteger(typ) {
996 if allowVersion != nil && !allowVersion(go1_22) {
997 return bad("requires go1.22 or later")
998 }
999 return orig, nil, "", false, true
1000 }
1001 case *Array:
1002 return Typ[Int], typ.elem, "", false, true
1003 case *Slice:
1004 return Typ[Int], typ.elem, "", false, true
1005 case *Map:
1006 return typ.key, typ.elem, "", false, true
1007 case *Chan:
1008 if typ.dir == SendOnly {
1009 return bad("receive from send-only channel")
1010 }
1011 return typ.elem, nil, "", false, true
1012 case *Signature:
1013
1014 if !buildcfg.Experiment.RangeFunc {
1015 break
1016 }
1017 assert(typ.Recv() == nil)
1018 switch {
1019 case typ.Params().Len() != 1:
1020 return bad("func must be func(yield func(...) bool): wrong argument count")
1021 case toSig(typ.Params().At(0).Type()) == nil:
1022 return bad("func must be func(yield func(...) bool): argument is not func")
1023 case typ.Results().Len() != 0:
1024 return bad("func must be func(yield func(...) bool): unexpected results")
1025 }
1026 cb := toSig(typ.Params().At(0).Type())
1027 assert(cb.Recv() == nil)
1028 switch {
1029 case cb.Params().Len() > 2:
1030 return bad("func must be func(yield func(...) bool): yield func has too many parameters")
1031 case cb.Results().Len() != 1 || !isBoolean(cb.Results().At(0).Type()):
1032 return bad("func must be func(yield func(...) bool): yield func does not return bool")
1033 }
1034 if cb.Params().Len() >= 1 {
1035 key = cb.Params().At(0).Type()
1036 }
1037 if cb.Params().Len() >= 2 {
1038 val = cb.Params().At(1).Type()
1039 }
1040 return key, val, "", true, true
1041 }
1042 return
1043 }
1044
View as plain text