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