1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file implements typechecking of statements.
14 . "internal/types/errors"
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")
23 if check.conf._Trace {
24 check.trace(body.Pos(), "-- %s: %s", name, sig)
27 // set function scope extent
28 sig.scope.pos = body.Pos()
29 sig.scope.end = body.End()
31 // save/restore current environment and set up function environment
32 // (and use 0 indentation at function start)
33 defer func(env environment, indent int) {
34 check.environment = env
36 }(check.environment, check.indent)
37 check.environment = environment{
45 check.stmtList(0, body.List)
51 if sig.results.Len() > 0 && !check.isTerminating(body, "") {
52 check.error(atPos(body.Rbrace), MissingReturn, "missing return")
55 // spec: "Implementation restriction: A compiler may make it illegal to
56 // declare a variable inside a function body if the variable is never used."
57 check.usage(sig.scope)
60 func (check *Checker) usage(scope *Scope) {
62 for name, elem := range scope.elems {
63 elem = resolve(name, elem)
64 if v, _ := elem.(*Var); v != nil && !v.used {
65 unused = append(unused, v)
68 sort.Slice(unused, func(i, j int) bool {
69 return cmpPos(unused[i].pos, unused[j].pos) < 0
71 for _, v := range unused {
72 check.softErrorf(v, UnusedVar, "%s declared and not used", v.name)
75 for _, scope := range scope.children {
76 // Don't go inside function literal scopes a second time;
77 // they are handled explicitly by funcBody.
84 // stmtContext is a bitset describing which
85 // control-flow statements are permissible,
86 // and provides additional context information
87 // for better error messages.
91 // permissible control-flow statements
92 breakOk stmtContext = 1 << iota
96 // additional context information
101 func (check *Checker) simpleStmt(s ast.Stmt) {
107 func trimTrailingEmptyStmts(list []ast.Stmt) []ast.Stmt {
108 for i := len(list); i > 0; i-- {
109 if _, ok := list[i-1].(*ast.EmptyStmt); !ok {
116 func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
117 ok := ctxt&fallthroughOk != 0
118 inner := ctxt &^ fallthroughOk
119 list = trimTrailingEmptyStmts(list) // trailing empty statements are "invisible" to fallthrough analysis
120 for i, s := range list {
122 if ok && i+1 == len(list) {
123 inner |= fallthroughOk
129 func (check *Checker) multipleDefaults(list []ast.Stmt) {
131 for _, s := range list {
133 switch c := s.(type) {
134 case *ast.CaseClause:
135 if len(c.List) == 0 {
138 case *ast.CommClause:
143 check.error(s, InvalidSyntaxTree, "case/communication clause expected")
147 check.errorf(d, DuplicateDefault, "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
155 func (check *Checker) openScope(node ast.Node, comment string) {
156 scope := NewScope(check.scope, node.Pos(), node.End(), comment)
157 check.recordScope(node, scope)
161 func (check *Checker) closeScope() {
162 check.scope = check.scope.Parent()
165 func assignOp(op token.Token) token.Token {
166 // token_test.go verifies the token ordering this function relies on
167 if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
168 return op + (token.ADD - token.ADD_ASSIGN)
173 func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
177 switch check.rawExpr(nil, &x, call, nil, false) {
179 msg = "requires function call, not conversion"
185 msg = "discards result of"
192 check.errorf(&x, code, "%s %s %s", keyword, msg, &x)
195 // goVal returns the Go value for val, or nil.
196 func goVal(val constant.Value) any {
197 // val should exist, but be conservative and check
201 // Match implementation restriction of other compilers.
202 // gc only checks duplicates for integer, floating-point
203 // and string values, so only create Go values for these
207 if x, ok := constant.Int64Val(val); ok {
210 if x, ok := constant.Uint64Val(val); ok {
214 if x, ok := constant.Float64Val(val); ok {
217 case constant.String:
218 return constant.StringVal(val)
223 // A valueMap maps a case value (of a basic Go type) to a list of positions
224 // where the same case value appeared, together with the corresponding case
226 // Since two case values may have the same "underlying" value but different
227 // types we need to also check the value's types (e.g., byte(1) vs myByte(1))
228 // when the switch expression is of interface type.
230 valueMap map[any][]valueType // underlying Go value -> valueType
237 func (check *Checker) caseValues(x *operand, values []ast.Expr, seen valueMap) {
239 for _, e := range values {
241 check.expr(nil, &v, e)
242 if x.mode == invalid || v.mode == invalid {
245 check.convertUntyped(&v, x.typ)
246 if v.mode == invalid {
249 // Order matters: By comparing v against x, error positions are at the case values.
250 res := v // keep original v unchanged
251 check.comparison(&res, x, token.EQL, true)
252 if res.mode == invalid {
255 if v.mode != constant_ {
256 continue L // we're done
258 // look for duplicate values
259 if val := goVal(v.val); val != nil {
260 // look for duplicate types for a given value
261 // (quadratic algorithm, but these lists tend to be very short)
262 for _, vt := range seen[val] {
263 if Identical(v.typ, vt.typ) {
264 check.errorf(&v, DuplicateCase, "duplicate case %s in expression switch", &v)
265 check.error(atPos(vt.pos), DuplicateCase, "\tprevious case") // secondary error, \t indented
269 seen[val] = append(seen[val], valueType{v.Pos(), v.typ})
274 // isNil reports whether the expression e denotes the predeclared value nil.
275 func (check *Checker) isNil(e ast.Expr) bool {
276 // The only way to express the nil value is by literally writing nil (possibly in parentheses).
277 if name, _ := unparen(e).(*ast.Ident); name != nil {
278 _, ok := check.lookup(name.Name).(*Nil)
284 // If the type switch expression is invalid, x is nil.
285 func (check *Checker) caseTypes(x *operand, types []ast.Expr, seen map[Type]ast.Expr) (T Type) {
288 for _, e := range types {
289 // The spec allows the value nil instead of a type.
292 check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings
299 // look for duplicate types
300 // (quadratic algorithm, but type switches tend to be reasonably small)
301 for t, other := range seen {
302 if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
303 // talk about "case" rather than "type" because of nil case
306 Ts = TypeString(T, check.qualifier)
308 check.errorf(e, DuplicateCase, "duplicate case %s in type switch", Ts)
309 check.error(other, DuplicateCase, "\tprevious case") // secondary error, \t indented
314 if x != nil && T != nil {
315 check.typeAssertion(e, x, T, true)
321 // TODO(gri) Once we are certain that typeHash is correct in all situations, use this version of caseTypes instead.
322 // (Currently it may be possible that different types have identical names and import paths due to ImporterFrom.)
324 // func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[string]ast.Expr) (T Type) {
327 // for _, e := range types {
328 // // The spec allows the value nil instead of a type.
330 // if check.isNil(e) {
331 // check.expr(nil, &dummy, e) // run e through expr so we get the usual Info recordings
333 // hash = "<nil>" // avoid collision with a type named nil
335 // T = check.varType(e)
339 // hash = typeHash(T, nil)
341 // // look for duplicate types
342 // if other := seen[hash]; other != nil {
343 // // talk about "case" rather than "type" because of nil case
346 // Ts = TypeString(T, check.qualifier)
349 // err.code = DuplicateCase
350 // err.errorf(e, "duplicate case %s in type switch", Ts)
351 // err.errorf(other, "previous case")
352 // check.report(&err)
357 // check.typeAssertion(e.Pos(), x, xtyp, T)
363 // stmt typechecks statement s.
364 func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
365 // statements must end with the same top scope as they started with
367 defer func(scope *Scope) {
368 // don't check if code is panicking
369 if p := recover(); p != nil {
372 assert(scope == check.scope)
376 // process collected function literals before scope changes
377 defer check.processDelayed(len(check.delayed))
379 // reset context for statements of inner blocks
380 inner := ctxt &^ (fallthroughOk | finalSwitchCase | inTypeSwitch)
382 switch s := s.(type) {
383 case *ast.BadStmt, *ast.EmptyStmt:
387 check.declStmt(s.Decl)
389 case *ast.LabeledStmt:
390 check.hasLabel = true
391 check.stmt(ctxt, s.Stmt)
394 // spec: "With the exception of specific built-in functions,
395 // function and method calls and receive operations can appear
396 // in statement context. Such statements may be parenthesized."
398 kind := check.rawExpr(nil, &x, s.X, nil, false)
403 if kind == statement {
409 msg = "must be called"
410 code = UncalledBuiltin
412 msg = "is not an expression"
415 check.errorf(&x, code, "%s %s", &x, msg)
419 check.expr(nil, &ch, s.Chan)
420 check.expr(nil, &val, s.Value)
421 if ch.mode == invalid || val.mode == invalid {
424 u := coreType(ch.typ)
426 check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to %s: no core type", &ch)
431 check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to non-channel %s", &ch)
434 if uch.dir == RecvOnly {
435 check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch)
438 check.assignment(&val, uch.elem, "send")
440 case *ast.IncDecStmt:
448 check.errorf(inNode(s, s.TokPos), InvalidSyntaxTree, "unknown inc/dec operation %s", s.Tok)
453 check.expr(nil, &x, s.X)
454 if x.mode == invalid {
457 if !allNumeric(x.typ) {
458 check.errorf(s.X, NonNumericIncDec, invalidOp+"%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
462 Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
463 check.binary(&x, nil, s.X, Y, op, s.TokPos)
464 if x.mode == invalid {
467 check.assignVar(s.X, nil, &x)
469 case *ast.AssignStmt:
471 case token.ASSIGN, token.DEFINE:
473 check.error(s, InvalidSyntaxTree, "missing lhs in assignment")
476 if s.Tok == token.DEFINE {
477 check.shortVarDecl(inNode(s, s.TokPos), s.Lhs, s.Rhs)
479 // regular assignment
480 check.assignVars(s.Lhs, s.Rhs)
484 // assignment operations
485 if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
486 check.errorf(inNode(s, s.TokPos), MultiValAssignOp, "assignment operation %s requires single-valued expressions", s.Tok)
489 op := assignOp(s.Tok)
490 if op == token.ILLEGAL {
491 check.errorf(atPos(s.TokPos), InvalidSyntaxTree, "unknown assignment operation %s", s.Tok)
495 check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op, s.TokPos)
496 if x.mode == invalid {
499 check.assignVar(s.Lhs[0], nil, &x)
503 check.suspendedCall("go", s.Call)
506 check.suspendedCall("defer", s.Call)
508 case *ast.ReturnStmt:
509 res := check.sig.results
510 // Return with implicit results allowed for function with named results.
511 // (If one is named, all are named.)
512 if len(s.Results) == 0 && res.Len() > 0 && res.vars[0].name != "" {
513 // spec: "Implementation restriction: A compiler may disallow an empty expression
514 // list in a "return" statement if a different entity (constant, type, or variable)
515 // with the same name as a result parameter is in scope at the place of the return."
516 for _, obj := range res.vars {
517 if alt := check.lookup(obj.name); alt != nil && alt != obj {
518 check.errorf(s, OutOfScopeResult, "result parameter %s not in scope at return", obj.name)
519 check.errorf(alt, OutOfScopeResult, "\tinner declaration of %s", obj)
528 check.initVars(lhs, s.Results, s)
531 case *ast.BranchStmt:
533 check.hasLabel = true
534 return // checked in 2nd pass (check.labels)
538 if ctxt&breakOk == 0 {
539 check.error(s, MisplacedBreak, "break not in for, switch, or select statement")
542 if ctxt&continueOk == 0 {
543 check.error(s, MisplacedContinue, "continue not in for statement")
545 case token.FALLTHROUGH:
546 if ctxt&fallthroughOk == 0 {
549 case ctxt&finalSwitchCase != 0:
550 msg = "cannot fallthrough final case in switch"
551 case ctxt&inTypeSwitch != 0:
552 msg = "cannot fallthrough in type switch"
554 msg = "fallthrough statement out of place"
556 check.error(s, MisplacedFallthrough, msg)
559 check.errorf(s, InvalidSyntaxTree, "branch statement: %s", s.Tok)
563 check.openScope(s, "block")
564 defer check.closeScope()
566 check.stmtList(inner, s.List)
569 check.openScope(s, "if")
570 defer check.closeScope()
572 check.simpleStmt(s.Init)
574 check.expr(nil, &x, s.Cond)
575 if x.mode != invalid && !allBoolean(x.typ) {
576 check.error(s.Cond, InvalidCond, "non-boolean condition in if statement")
578 check.stmt(inner, s.Body)
579 // The parser produces a correct AST but if it was modified
580 // elsewhere the else branch may be invalid. Check again.
581 switch s.Else.(type) {
582 case nil, *ast.BadStmt:
583 // valid or error already reported
584 case *ast.IfStmt, *ast.BlockStmt:
585 check.stmt(inner, s.Else)
587 check.error(s.Else, InvalidSyntaxTree, "invalid else branch in if statement")
590 case *ast.SwitchStmt:
592 check.openScope(s, "switch")
593 defer check.closeScope()
595 check.simpleStmt(s.Init)
598 check.expr(nil, &x, s.Tag)
599 // By checking assignment of x to an invisible temporary
600 // (as a compiler would), we get all the relevant checks.
601 check.assignment(&x, nil, "switch expression")
602 if x.mode != invalid && !Comparable(x.typ) && !hasNil(x.typ) {
603 check.errorf(&x, InvalidExprSwitch, "cannot switch on %s (%s is not comparable)", &x, x.typ)
607 // spec: "A missing switch expression is
608 // equivalent to the boolean value true."
611 x.val = constant.MakeBool(true)
612 x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
615 check.multipleDefaults(s.Body.List)
617 seen := make(valueMap) // map of seen case values to positions and types
618 for i, c := range s.Body.List {
619 clause, _ := c.(*ast.CaseClause)
621 check.error(c, InvalidSyntaxTree, "incorrect expression switch case")
624 check.caseValues(&x, clause.List, seen)
625 check.openScope(clause, "case")
627 if i+1 < len(s.Body.List) {
628 inner |= fallthroughOk
630 inner |= finalSwitchCase
632 check.stmtList(inner, clause.Body)
636 case *ast.TypeSwitchStmt:
637 inner |= breakOk | inTypeSwitch
638 check.openScope(s, "type switch")
639 defer check.closeScope()
641 check.simpleStmt(s.Init)
643 // A type switch guard must be of the form:
645 // TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
647 // The parser is checking syntactic correctness;
648 // remaining syntactic errors are considered AST errors here.
649 // TODO(gri) better factoring of error handling (invalid ASTs)
651 var lhs *ast.Ident // lhs identifier or nil
653 switch guard := s.Assign.(type) {
656 case *ast.AssignStmt:
657 if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
658 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
662 lhs, _ = guard.Lhs[0].(*ast.Ident)
664 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
669 // _ := x.(type) is an invalid short variable declaration
670 check.softErrorf(lhs, NoNewVar, "no new variable on left side of :=")
671 lhs = nil // avoid declared and not used error below
673 check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
679 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
683 // rhs must be of the form: expr.(type) and expr must be an ordinary interface
684 expr, _ := rhs.(*ast.TypeAssertExpr)
685 if expr == nil || expr.Type != nil {
686 check.error(s, InvalidSyntaxTree, "incorrect form of type switch guard")
690 check.expr(nil, &x, expr.X)
691 if x.mode == invalid {
694 // TODO(gri) we may want to permit type switches on type parameter values at some point
695 var sx *operand // switch expression against which cases are compared against; nil if invalid
696 if isTypeParam(x.typ) {
697 check.errorf(&x, InvalidTypeSwitch, "cannot use type switch on type parameter value %s", &x)
699 if _, ok := under(x.typ).(*Interface); ok {
702 check.errorf(&x, InvalidTypeSwitch, "%s is not an interface", &x)
706 check.multipleDefaults(s.Body.List)
708 var lhsVars []*Var // list of implicitly declared lhs variables
709 seen := make(map[Type]ast.Expr) // map of seen types to positions
710 for _, s := range s.Body.List {
711 clause, _ := s.(*ast.CaseClause)
713 check.error(s, InvalidSyntaxTree, "incorrect type switch case")
716 // Check each type in this type switch case.
717 T := check.caseTypes(sx, clause.List, seen)
718 check.openScope(clause, "case")
719 // If lhs exists, declare a corresponding variable in the case-local scope.
721 // spec: "The TypeSwitchGuard may include a short variable declaration.
722 // When that form is used, the variable is declared at the beginning of
723 // the implicit block in each clause. In clauses with a case listing
724 // exactly one type, the variable has that type; otherwise, the variable
725 // has the type of the expression in the TypeSwitchGuard."
726 if len(clause.List) != 1 || T == nil {
729 obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
730 scopePos := clause.Pos() + token.Pos(len("default")) // for default clause (len(List) == 0)
731 if n := len(clause.List); n > 0 {
732 scopePos = clause.List[n-1].End()
734 check.declare(check.scope, nil, obj, scopePos)
735 check.recordImplicit(clause, obj)
736 // For the "declared and not used" error, all lhs variables act as
737 // one; i.e., if any one of them is 'used', all of them are 'used'.
738 // Collect them for later analysis.
739 lhsVars = append(lhsVars, obj)
741 check.stmtList(inner, clause.Body)
745 // If lhs exists, we must have at least one lhs variable that was used.
748 for _, v := range lhsVars {
752 v.used = true // avoid usage error when checking entire function
755 check.softErrorf(lhs, UnusedVar, "%s declared and not used", lhs.Name)
759 case *ast.SelectStmt:
762 check.multipleDefaults(s.Body.List)
764 for _, s := range s.Body.List {
765 clause, _ := s.(*ast.CommClause)
767 continue // error reported before
770 // clause.Comm must be a SendStmt, RecvStmt, or default case
772 var rhs ast.Expr // rhs of RecvStmt, or nil
773 switch s := clause.Comm.(type) {
774 case nil, *ast.SendStmt:
776 case *ast.AssignStmt:
784 // if present, rhs must be a receive operation
786 if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
792 check.error(clause.Comm, InvalidSelectCase, "select case must be send or receive (possibly with assignment)")
796 check.openScope(s, "case")
797 if clause.Comm != nil {
798 check.stmt(inner, clause.Comm)
800 check.stmtList(inner, clause.Body)
805 inner |= breakOk | continueOk
806 check.openScope(s, "for")
807 defer check.closeScope()
809 check.simpleStmt(s.Init)
812 check.expr(nil, &x, s.Cond)
813 if x.mode != invalid && !allBoolean(x.typ) {
814 check.error(s.Cond, InvalidCond, "non-boolean condition in for statement")
817 check.simpleStmt(s.Post)
818 // spec: "The init statement may be a short variable
819 // declaration, but the post statement must not."
820 if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
821 check.softErrorf(s, InvalidPostDecl, "cannot declare in post statement")
822 // Don't call useLHS here because we want to use the lhs in
823 // this erroneous statement so that we don't get errors about
824 // these lhs variables being declared and not used.
825 check.use(s.Lhs...) // avoid follow-up errors
827 check.stmt(inner, s.Body)
830 inner |= breakOk | continueOk
831 check.rangeStmt(inner, s)
834 check.error(s, InvalidSyntaxTree, "invalid statement")
838 func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
839 // Convert go/ast form to local variables.
841 type identType = ast.Ident
842 identName := func(n *identType) string { return n.Name }
843 sKey, sValue := s.Key, s.Value
844 var sExtra ast.Expr = nil
845 isDef := s.Tok == token.DEFINE
847 noNewVarPos := inNode(s, s.TokPos)
849 // Everything from here on is shared between cmd/compile/internal/types2 and go/types.
851 // check expression to iterate over
853 check.expr(nil, &x, rangeVar)
855 // determine key/value types
857 if x.mode != invalid {
858 // Ranging over a type parameter is permitted if it has a core type.
859 k, v, cause, isFunc, ok := rangeKeyVal(x.typ)
861 case !ok && cause != "":
862 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s: %s", &x, cause)
864 check.softErrorf(&x, InvalidRangeExpr, "cannot range over %s", &x)
865 case k == nil && sKey != nil:
866 check.softErrorf(sKey, InvalidIterVar, "range over %s permits no iteration variables", &x)
867 case v == nil && sValue != nil:
868 check.softErrorf(sValue, InvalidIterVar, "range over %s permits only one iteration variable", &x)
870 check.softErrorf(sExtra, InvalidIterVar, "range clause permits at most two iteration variables")
871 case isFunc && ((k == nil) != (sKey == nil) || (v == nil) != (sValue == nil)):
875 count = "no iteration variables"
877 count = "one iteration variable"
879 count = "two iteration variables"
881 check.softErrorf(&x, InvalidIterVar, "range over %s must have %s", &x, count)
886 // Open the for-statement block scope now, after the range clause.
887 // Iteration variables declared with := need to go in this scope (was go.dev/issue/51437).
888 check.openScope(s, "range")
889 defer check.closeScope()
891 // check assignment to/declaration of iteration variables
892 // (irregular assignment, cannot easily map to existing assignment checks)
894 // lhs expressions and initialization value (rhs) types
895 lhs := [2]expr{sKey, sValue}
896 rhs := [2]Type{key, val} // key, val may be nil
899 // short variable declaration
901 for i, lhs := range lhs {
906 // determine lhs variable
908 if ident, _ := lhs.(*identType); ident != nil {
909 // declare new variable
910 name := identName(ident)
911 obj = NewVar(ident.Pos(), check.pkg, name, nil)
912 check.recordDef(ident, obj)
913 // _ variables don't count as new variables
915 vars = append(vars, obj)
918 check.errorf(lhs, InvalidSyntaxTree, "cannot declare %s", lhs)
919 obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
922 // initialize lhs variable
923 if typ := rhs[i]; typ != nil {
925 x.expr = lhs // we don't have a better rhs expression to use here
927 check.initVar(obj, &x, "range clause")
929 obj.typ = Typ[Invalid]
930 obj.used = true // don't complain about unused variable
936 scopePos := s.Body.Pos()
937 for _, obj := range vars {
938 check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
941 check.error(noNewVarPos, NoNewVar, "no new variables on left side of :=")
944 // ordinary assignment
945 for i, lhs := range lhs {
949 if typ := rhs[i]; typ != nil {
951 x.expr = lhs // we don't have a better rhs expression to use here
953 check.assignVar(lhs, nil, &x)
958 check.stmt(inner, s.Body)
961 // rangeKeyVal returns the key and value type produced by a range clause
962 // over an expression of type typ. If the range clause is not permitted,
963 // rangeKeyVal returns ok = false. When ok = false, rangeKeyVal may also
964 // return a reason in cause.
965 func rangeKeyVal(typ Type) (key, val Type, cause string, isFunc, ok bool) {
966 bad := func(cause string) (Type, Type, string, bool, bool) {
967 return Typ[Invalid], Typ[Invalid], cause, false, false
969 toSig := func(t Type) *Signature {
970 sig, _ := coreType(t).(*Signature)
975 switch typ := arrayPtrDeref(coreType(typ)).(type) {
977 return bad("no core type")
980 return Typ[Int], universeRune, "", false, true // use 'rune' name
983 return orig, nil, "", false, true
986 return Typ[Int], typ.elem, "", false, true
988 return Typ[Int], typ.elem, "", false, true
990 return typ.key, typ.elem, "", false, true
992 if typ.dir == SendOnly {
993 return bad("receive from send-only channel")
995 return typ.elem, nil, "", false, true
997 if !buildcfg.Experiment.RangeFunc {
1000 assert(typ.Recv() == nil)
1002 case typ.Params().Len() != 1:
1003 return bad("func must be func(yield func(...) bool): wrong argument count")
1004 case toSig(typ.Params().At(0).Type()) == nil:
1005 return bad("func must be func(yield func(...) bool): argument is not func")
1006 case typ.Results().Len() != 0:
1007 return bad("func must be func(yield func(...) bool): unexpected results")
1009 cb := toSig(typ.Params().At(0).Type())
1010 assert(cb.Recv() == nil)
1012 case cb.Params().Len() > 2:
1013 return bad("func must be func(yield func(...) bool): yield func has too many parameters")
1014 case cb.Results().Len() != 1 || !isBoolean(cb.Results().At(0).Type()):
1015 return bad("func must be func(yield func(...) bool): yield func does not return bool")
1017 if cb.Params().Len() >= 1 {
1018 key = cb.Params().At(0).Type()
1020 if cb.Params().Len() >= 2 {
1021 val = cb.Params().At(1).Type()
1023 return key, val, "", true, true