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 if elem := check.chanElem(inNode(s, s.Arrow), &ch, false); elem != nil {
470 check.assignment(&val, elem, "send")
471 }
472
473 case *ast.IncDecStmt:
474 var op token.Token
475 switch s.Tok {
476 case token.INC:
477 op = token.ADD
478 case token.DEC:
479 op = token.SUB
480 default:
481 check.errorf(inNode(s, s.TokPos), InvalidSyntaxTree, "unknown inc/dec operation %s", s.Tok)
482 return
483 }
484
485 var x operand
486 check.expr(nil, &x, s.X)
487 if x.mode == invalid {
488 return
489 }
490 if !allNumeric(x.typ) {
491 check.errorf(s.X, NonNumericIncDec, invalidOp+"%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
492 return
493 }
494
495 Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"}
496 check.binary(&x, nil, s.X, Y, op, s.TokPos)
497 if x.mode == invalid {
498 return
499 }
500 check.assignVar(s.X, nil, &x, "assignment")
501
502 case *ast.AssignStmt:
503 switch s.Tok {
504 case token.ASSIGN, token.DEFINE:
505 if len(s.Lhs) == 0 {
506 check.error(s, InvalidSyntaxTree, "missing lhs in assignment")
507 return
508 }
509 if s.Tok == token.DEFINE {
510 check.shortVarDecl(inNode(s, s.TokPos), s.Lhs, s.Rhs)
511 } else {
512
513 check.assignVars(s.Lhs, s.Rhs)
514 }
515
516 default:
517
518 if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
519 check.errorf(inNode(s, s.TokPos), MultiValAssignOp, "assignment operation %s requires single-valued expressions", s.Tok)
520 return
521 }
522 op := assignOp(s.Tok)
523 if op == token.ILLEGAL {
524 check.errorf(atPos(s.TokPos), InvalidSyntaxTree, "unknown assignment operation %s", s.Tok)
525 return
526 }
527 var x operand
528 check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op, s.TokPos)
529 if x.mode == invalid {
530 return
531 }
532 check.assignVar(s.Lhs[0], nil, &x, "assignment")
533 }
534
535 case *ast.GoStmt:
536 check.suspendedCall("go", s.Call)
537
538 case *ast.DeferStmt:
539 check.suspendedCall("defer", s.Call)
540
541 case *ast.ReturnStmt:
542 res := check.sig.results
543
544
545 if len(s.Results) == 0 && res.Len() > 0 && res.vars[0].name != "" {
546
547
548
549 for _, obj := range res.vars {
550 if alt := check.lookup(obj.name); alt != nil && alt != obj {
551 err := check.newError(OutOfScopeResult)
552 err.addf(s, "result parameter %s not in scope at return", obj.name)
553 err.addf(alt, "inner declaration of %s", obj)
554 err.report()
555
556 }
557 }
558 } else {
559 var lhs []*Var
560 if res.Len() > 0 {
561 lhs = res.vars
562 }
563 check.initVars(lhs, s.Results, s)
564 }
565
566 case *ast.BranchStmt:
567 if s.Label != nil {
568 check.hasLabel = true
569 return
570 }
571 switch s.Tok {
572 case token.BREAK:
573 if ctxt&breakOk == 0 {
574 check.error(s, MisplacedBreak, "break not in for, switch, or select statement")
575 }
576 case token.CONTINUE:
577 if ctxt&continueOk == 0 {
578 check.error(s, MisplacedContinue, "continue not in for statement")
579 }
580 case token.FALLTHROUGH:
581 if ctxt&fallthroughOk == 0 {
582 var msg string
583 switch {
584 case ctxt&finalSwitchCase != 0:
585 msg = "cannot fallthrough final case in switch"
586 case ctxt&inTypeSwitch != 0:
587 msg = "cannot fallthrough in type switch"
588 default:
589 msg = "fallthrough statement out of place"
590 }
591 check.error(s, MisplacedFallthrough, msg)
592 }
593 default:
594 check.errorf(s, InvalidSyntaxTree, "branch statement: %s", s.Tok)
595 }
596
597 case *ast.BlockStmt:
598 check.openScope(s, "block")
599 defer check.closeScope()
600
601 check.stmtList(inner, s.List)
602
603 case *ast.IfStmt:
604 check.openScope(s, "if")
605 defer check.closeScope()
606
607 check.simpleStmt(s.Init)
608 var x operand
609 check.expr(nil, &x, s.Cond)
610 if x.mode != invalid && !allBoolean(x.typ) {
611 check.error(s.Cond, InvalidCond, "non-boolean condition in if statement")
612 }
613 check.stmt(inner, s.Body)
614
615
616 switch s.Else.(type) {
617 case nil, *ast.BadStmt:
618
619 case *ast.IfStmt, *ast.BlockStmt:
620 check.stmt(inner, s.Else)
621 default:
622 check.error(s.Else, InvalidSyntaxTree, "invalid else branch in if statement")
623 }
624
625 case *ast.SwitchStmt:
626 inner |= breakOk
627 check.openScope(s, "switch")
628 defer check.closeScope()
629
630 check.simpleStmt(s.Init)
631 var x operand
632 if s.Tag != nil {
633 check.expr(nil, &x, s.Tag)
634
635
636 check.assignment(&x, nil, "switch expression")
637 if x.mode != invalid && !Comparable(x.typ) && !hasNil(x.typ) {
638 check.errorf(&x, InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ)
639 x.mode = invalid
640 }
641 } else {
642
643
644 x.mode = constant_
645 x.typ = Typ[Bool]
646 x.val = constant.MakeBool(true)
647 x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
648 }
649
650 check.multipleDefaults(s.Body.List)
651
652 seen := make(valueMap)
653 for i, c := range s.Body.List {
654 clause, _ := c.(*ast.CaseClause)
655 if clause == nil {
656 check.error(c, InvalidSyntaxTree, "incorrect expression switch case")
657 continue
658 }
659 check.caseValues(&x, clause.List, seen)
660 check.openScope(clause, "case")
661 inner := inner
662 if i+1 < len(s.Body.List) {
663 inner |= fallthroughOk
664 } else {
665 inner |= finalSwitchCase
666 }
667 check.stmtList(inner, clause.Body)
668 check.closeScope()
669 }
670
671 case *ast.TypeSwitchStmt:
672 inner |= breakOk | inTypeSwitch
673 check.openScope(s, "type switch")
674 defer check.closeScope()
675
676 check.simpleStmt(s.Init)
677
678
679
680
681
682
683
684
685
686 var lhs *ast.Ident
687 var rhs ast.Expr
688 switch guard := s.Assign.(type) {
689 case *ast.ExprStmt:
690 rhs = guard.X
691 case *ast.AssignStmt:
692 if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
693 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
694 return
695 }
696
697 lhs, _ = guard.Lhs[0].(*ast.Ident)
698 if lhs == nil {
699 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
700 return
701 }
702
703 if lhs.Name == "_" {
704
705 check.softErrorf(lhs, NoNewVar, "no new variable on left side of :=")
706 lhs = nil
707 } else {
708 check.recordDef(lhs, nil)
709 }
710
711 rhs = guard.Rhs[0]
712
713 default:
714 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
715 return
716 }
717
718
719 expr, _ := rhs.(*ast.TypeAssertExpr)
720 if expr == nil || expr.Type != nil {
721 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
722 return
723 }
724
725 var sx *operand
726 {
727 var x operand
728 check.expr(nil, &x, expr.X)
729 if x.mode != invalid {
730 if isTypeParam(x.typ) {
731 check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x)
732 } else if IsInterface(x.typ) {
733 sx = &x
734 } else {
735 check.errorf(&x, InvalidTypeSwitch, "%s is not an interface", &x)
736 }
737 }
738 }
739
740 check.multipleDefaults(s.Body.List)
741
742 var lhsVars []*Var
743 seen := make(map[Type]ast.Expr)
744 for _, s := range s.Body.List {
745 clause, _ := s.(*ast.CaseClause)
746 if clause == nil {
747 check.error(s, InvalidSyntaxTree, "incorrect type switch case")
748 continue
749 }
750
751 T := check.caseTypes(sx, clause.List, seen)
752 check.openScope(clause, "case")
753
754 if lhs != nil {
755 obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
756 check.declare(check.scope, nil, obj, clause.Colon)
757 check.recordImplicit(clause, obj)
758
759
760
761 lhsVars = append(lhsVars, obj)
762 }
763 check.stmtList(inner, clause.Body)
764 check.closeScope()
765 }
766
767
768 if lhs != nil {
769 var used bool
770 for _, v := range lhsVars {
771 if v.used {
772 used = true
773 }
774 v.used = true
775 }
776 if !used {
777 check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Name)
778 }
779 }
780
781 case *ast.SelectStmt:
782 inner |= breakOk
783
784 check.multipleDefaults(s.Body.List)
785
786 for _, s := range s.Body.List {
787 clause, _ := s.(*ast.CommClause)
788 if clause == nil {
789 continue
790 }
791
792
793 valid := false
794 var rhs ast.Expr
795 switch s := clause.Comm.(type) {
796 case nil, *ast.SendStmt:
797 valid = true
798 case *ast.AssignStmt:
799 if len(s.Rhs) == 1 {
800 rhs = s.Rhs[0]
801 }
802 case *ast.ExprStmt:
803 rhs = s.X
804 }
805
806
807 if rhs != nil {
808 if x, _ := ast.Unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
809 valid = true
810 }
811 }
812
813 if !valid {
814 check.error(clause.Comm, InvalidSelectCase, "select case must be send or receive (possibly with assignment)")
815 continue
816 }
817
818 check.openScope(s, "case")
819 if clause.Comm != nil {
820 check.stmt(inner, clause.Comm)
821 }
822 check.stmtList(inner, clause.Body)
823 check.closeScope()
824 }
825
826 case *ast.ForStmt:
827 inner |= breakOk | continueOk
828 check.openScope(s, "for")
829 defer check.closeScope()
830
831 check.simpleStmt(s.Init)
832 if s.Cond != nil {
833 var x operand
834 check.expr(nil, &x, s.Cond)
835 if x.mode != invalid && !allBoolean(x.typ) {
836 check.error(s.Cond, InvalidCond, "non-boolean condition in for statement")
837 }
838 }
839 check.simpleStmt(s.Post)
840
841
842 if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
843 check.softErrorf(s, InvalidPostDecl, "cannot declare in post statement")
844
845
846
847 check.use(s.Lhs...)
848 }
849 check.stmt(inner, s.Body)
850
851 case *ast.RangeStmt:
852 inner |= breakOk | continueOk
853 check.rangeStmt(inner, s)
854
855 default:
856 check.error(s, InvalidSyntaxTree, "invalid statement")
857 }
858 }
859
860 func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
861
862 type Expr = ast.Expr
863 type identType = ast.Ident
864 identName := func(n *identType) string { return n.Name }
865 sKey, sValue := s.Key, s.Value
866 var sExtra ast.Expr = nil
867 isDef := s.Tok == token.DEFINE
868 rangeVar := s.X
869 noNewVarPos := inNode(s, s.TokPos)
870
871
872
873
874 var x operand
875 check.expr(nil, &x, rangeVar)
876
877
878 var key, val Type
879 if x.mode != invalid {
880
881 k, v, cause, ok := rangeKeyVal(x.typ, func(v goVersion) bool {
882 return check.allowVersion(v)
883 })
884 switch {
885 case !ok && cause != "":
886 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s: %s", &x, cause)
887 case !ok:
888 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s", &x)
889 case k == nil && sKey != nil:
890 check.softErrorf(sKey, InvalidIterVar, "range over %s permits no iteration variables", &x)
891 case v == nil && sValue != nil:
892 check.softErrorf(sValue, InvalidIterVar, "range over %s permits only one iteration variable", &x)
893 case sExtra != nil:
894 check.softErrorf(sExtra, InvalidIterVar, "range clause permits at most two iteration variables")
895 }
896 key, val = k, v
897 }
898
899
900
901 check.openScope(s, "range")
902 defer check.closeScope()
903
904
905
906
907
908 lhs := [2]Expr{sKey, sValue}
909 rhs := [2]Type{key, val}
910
911 rangeOverInt := isInteger(x.typ)
912
913 if isDef {
914
915 var vars []*Var
916 for i, lhs := range lhs {
917 if lhs == nil {
918 continue
919 }
920
921
922 var obj *Var
923 if ident, _ := lhs.(*identType); ident != nil {
924
925 name := identName(ident)
926 obj = NewVar(ident.Pos(), check.pkg, name, nil)
927 check.recordDef(ident, obj)
928
929 if name != "_" {
930 vars = append(vars, obj)
931 }
932 } else {
933 check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs)
934 obj = NewVar(lhs.Pos(), check.pkg, "_", nil)
935 }
936 assert(obj.typ == nil)
937
938
939 typ := rhs[i]
940 if typ == nil || typ == Typ[Invalid] {
941
942 obj.typ = Typ[Invalid]
943 obj.used = true
944 continue
945 }
946
947 if rangeOverInt {
948 assert(i == 0)
949 check.initVar(obj, &x, "range clause")
950 } else {
951 var y operand
952 y.mode = value
953 y.expr = lhs
954 y.typ = typ
955 check.initVar(obj, &y, "assignment")
956 }
957 assert(obj.typ != nil)
958 }
959
960
961 if len(vars) > 0 {
962 scopePos := s.Body.Pos()
963 for _, obj := range vars {
964 check.declare(check.scope, nil , obj, scopePos)
965 }
966 } else {
967 check.error(noNewVarPos, NoNewVar, "no new variables on left side of :=")
968 }
969 } else if sKey != nil {
970
971 for i, lhs := range lhs {
972 if lhs == nil {
973 continue
974 }
975
976
977 typ := rhs[i]
978 if typ == nil || typ == Typ[Invalid] {
979 continue
980 }
981
982 if rangeOverInt {
983 assert(i == 0)
984 check.assignVar(lhs, nil, &x, "range clause")
985
986
987
988 if x.mode != invalid && !isInteger(x.typ) {
989 check.softErrorf(lhs, InvalidRangeExpr, "cannot use iteration variable of type %s", x.typ)
990 }
991 } else {
992 var y operand
993 y.mode = value
994 y.expr = lhs
995 y.typ = typ
996 check.assignVar(lhs, nil, &y, "assignment")
997 }
998 }
999 } else if rangeOverInt {
1000
1001
1002
1003
1004
1005
1006 check.assignment(&x, nil, "range clause")
1007 }
1008
1009 check.stmt(inner, s.Body)
1010 }
1011
1012
1013
1014
1015
1016
1017 func rangeKeyVal(typ Type, allowVersion func(goVersion) bool) (key, val Type, cause string, ok bool) {
1018 bad := func(cause string) (Type, Type, string, bool) {
1019 return Typ[Invalid], Typ[Invalid], cause, false
1020 }
1021
1022 orig := typ
1023 switch typ := arrayPtrDeref(coreType(typ)).(type) {
1024 case nil:
1025 return bad("no core type")
1026 case *Basic:
1027 if isString(typ) {
1028 return Typ[Int], universeRune, "", true
1029 }
1030 if isInteger(typ) {
1031 if allowVersion != nil && !allowVersion(go1_22) {
1032 return bad("requires go1.22 or later")
1033 }
1034 return orig, nil, "", true
1035 }
1036 case *Array:
1037 return Typ[Int], typ.elem, "", true
1038 case *Slice:
1039 return Typ[Int], typ.elem, "", true
1040 case *Map:
1041 return typ.key, typ.elem, "", true
1042 case *Chan:
1043 if typ.dir == SendOnly {
1044 return bad("receive from send-only channel")
1045 }
1046 return typ.elem, nil, "", true
1047 case *Signature:
1048 if !buildcfg.Experiment.RangeFunc && allowVersion != nil && !allowVersion(go1_23) {
1049 return bad("requires go1.23 or later")
1050 }
1051
1052 switch {
1053 case typ.Params().Len() != 1:
1054 return bad("func must be func(yield func(...) bool): wrong argument count")
1055 case typ.Results().Len() != 0:
1056 return bad("func must be func(yield func(...) bool): unexpected results")
1057 }
1058 assert(typ.Recv() == nil)
1059
1060 cb, _ := coreType(typ.Params().At(0).Type()).(*Signature)
1061 switch {
1062 case cb == nil:
1063 return bad("func must be func(yield func(...) bool): argument is not func")
1064 case cb.Params().Len() > 2:
1065 return bad("func must be func(yield func(...) bool): yield func has too many parameters")
1066 case cb.Results().Len() != 1 || !Identical(cb.Results().At(0).Type(), universeBool):
1067
1068 if cb.Results().Len() == 1 && isBoolean(cb.Results().At(0).Type()) {
1069 return bad("func must be func(yield func(...) bool): yield func returns user-defined boolean, not bool")
1070 } else {
1071 return bad("func must be func(yield func(...) bool): yield func does not return bool")
1072 }
1073 }
1074 assert(cb.Recv() == nil)
1075
1076 if cb.Params().Len() >= 1 {
1077 key = cb.Params().At(0).Type()
1078 }
1079 if cb.Params().Len() >= 2 {
1080 val = cb.Params().At(1).Type()
1081 }
1082 return key, val, "", true
1083 }
1084 return
1085 }
1086
View as plain text