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