// Code generated by "go test -run=Generate -write=all"; DO NOT EDIT.// Source: ../../cmd/compile/internal/types2/range.go// Copyright 2025 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.// This file implements typechecking of range statements.package typesimport (.)// rangeStmt type-checks a range statement of form//// for sKey, sValue = range rangeVar { ... }//// where sKey, sValue, sExtra may be nil. isDef indicates whether these// variables are assigned to only (=) or whether there is a short variable// declaration (:=). If the latter and there are no variables, an error is// reported at noNewVarPos.func ( *Checker) ( stmtContext, *ast.RangeStmt, positioner, , , , ast.Expr, bool) {// check expression to iterate overvaroperand// From the spec: // The range expression x is evaluated before beginning the loop, // with one exception: if at most one iteration variable is present // and x or len(x) is constant, the range expression is not evaluated. // So we have to be careful not to evaluate the arg in the // described situation. .hasCallOrRecv = false .expr(nil, &, )ifisTypes2 && .mode != invalid && == nil && !.hasCallOrRecv {if , := arrayPtrDeref(under(.typ)).(*Array); {for {// Put constant info on the thing inside parentheses. // That's where (*../noder/writer).expr expects it. // See issue 73476. , := .(*ast.ParenExpr)if ! {break } = .X }// Override type of rangeVar to be a constant // (and thus side-effects will not be computed // by the backend). .record(&operand{mode: constant_,expr: ,typ: Typ[Int],val: constant.MakeInt64(.len),id: .id, }) } }// determine key/value typesvar , Typeif .mode != invalid { , , , := rangeKeyVal(, .typ, func( goVersion) bool {return .allowVersion() })switch {case ! && != "": .softErrorf(&, InvalidRangeExpr, "cannot range over %s: %s", &, )case !: .softErrorf(&, InvalidRangeExpr, "cannot range over %s", &)case == nil && != nil: .softErrorf(, InvalidIterVar, "range over %s permits no iteration variables", &)case == nil && != nil: .softErrorf(, InvalidIterVar, "range over %s permits only one iteration variable", &)case != nil: .softErrorf(, InvalidIterVar, "range clause permits at most two iteration variables") } , = , }// Open the for-statement block scope now, after the range clause. // Iteration variables declared with := need to go in this scope (was go.dev/issue/51437). .openScope(, "range")defer .closeScope()// check assignment to/declaration of iteration variables // (irregular assignment, cannot easily map to existing assignment checks)// lhs expressions and initialization value (rhs) types := [2]ast.Expr{, } // sKey, sValue may be nil := [2]Type{, } // key, val may be nil := isInteger(.typ)if {// short variable declarationvar []*Varfor , := range {if == nil {continue }// determine lhs variablevar *Varif , := .(*ast.Ident); != nil {// declare new variable := .Name = newVar(LocalVar, .Pos(), .pkg, , nil) .recordDef(, )// _ variables don't count as new variablesif != "_" { = append(, ) } } else { .errorf(, InvalidSyntaxTree, "cannot declare %s", ) = newVar(LocalVar, .Pos(), .pkg, "_", nil) // dummy variable }assert(.typ == nil)// initialize lhs iteration variable, if any := []if == nil || == Typ[Invalid] {// typ == Typ[Invalid] can happen if allowVersion fails. .typ = Typ[Invalid] .usedVars[] = true// don't complain about unused variablecontinue }if {assert( == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt) .initVar(, &, "range clause") } else {varoperand .mode = value .expr = // we don't have a better rhs expression to use here .typ = .initVar(, &, "assignment") // error is on variable, use "assignment" not "range clause" }assert(.typ != nil) }// declare variablesiflen() > 0 { := .Body.Pos()for , := range { .declare(.scope, nil/* recordDef already called */, , ) } } else { .error(, NoNewVar, "no new variables on left side of :=") } } elseif != nil/* lhs[0] != nil */ {// ordinary assignmentfor , := range {if == nil {continue }// assign to lhs iteration variable, if any := []if == nil || == Typ[Invalid] {continue }if {assert( == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt) .assignVar(, nil, &, "range clause")// If the assignment succeeded, if x was untyped before, it now // has a type inferred via the assignment. It must be an integer. // (go.dev/issues/67027)if .mode != invalid && !isInteger(.typ) { .softErrorf(, InvalidRangeExpr, "cannot use iteration variable of type %s", .typ) } } else {varoperand .mode = value .expr = // we don't have a better rhs expression to use here .typ = .assignVar(, nil, &, "assignment") // error is on variable, use "assignment" not "range clause" } } } elseif {// If we don't have any iteration variables, we still need to // check that a (possibly untyped) integer range expression x // is valid. // We do this by checking the assignment _ = x. This ensures // that an untyped x can be converted to a value of its default // type (rune or int). .assignment(&, nil, "range clause") } .stmt(, .Body)}// rangeKeyVal returns the key and value type produced by a range clause// over an expression of type orig.// If allowVersion != nil, it is used to check the required language version.// If the range clause is not permitted, rangeKeyVal returns ok = false.// When ok = false, rangeKeyVal may also return a reason in cause.// The check parameter is only used in case of an error; it may be nil.func rangeKeyVal( *Checker, Type, func(goVersion) bool) (, Type, string, bool) { := func( string) (Type, Type, string, bool) {returnTyp[Invalid], Typ[Invalid], , false } , := commonUnder(, func(, Type) *typeError {// A channel must permit receive operations.if , := .(*Chan); != nil && .dir == SendOnly {returntypeErrorf("receive from send-only channel %s", ) }returnnil })if == nil {return (.format()) }switch typ := arrayPtrDeref().(type) {case *Basic:ifisString() {returnTyp[Int], universeRune, "", true// use 'rune' name }ifisInteger() {if != nil && !(go1_22) {return ("requires go1.22 or later") }return , nil, "", true }case *Array:returnTyp[Int], .elem, "", truecase *Slice:returnTyp[Int], .elem, "", truecase *Map:return .key, .elem, "", truecase *Chan:assert(.dir != SendOnly)return .elem, nil, "", truecase *Signature:if !buildcfg.Experiment.RangeFunc && != nil && !(go1_23) {return ("requires go1.23 or later") }// check iterator arityswitch {case .Params().Len() != 1:return ("func must be func(yield func(...) bool): wrong argument count")case .Results().Len() != 0:return ("func must be func(yield func(...) bool): unexpected results") }assert(.Recv() == nil)// check iterator argument type , := commonUnder(.Params().At(0).Type(), nil) , := .(*Signature)switch {case == nil:if != nil {return (.sprintf("func must be func(yield func(...) bool): in yield type, %s", .format())) } else {return ("func must be func(yield func(...) bool): argument is not func") }case .Params().Len() > 2:return ("func must be func(yield func(...) bool): yield func has too many parameters")case .Results().Len() != 1 || !Identical(.Results().At(0).Type(), universeBool):// see go.dev/issues/71131, go.dev/issues/71164if .Results().Len() == 1 && isBoolean(.Results().At(0).Type()) {return ("func must be func(yield func(...) bool): yield func returns user-defined boolean, not bool") } else {return ("func must be func(yield func(...) bool): yield func does not return bool") } }assert(.Recv() == nil)// determine key and value types, if anyif .Params().Len() >= 1 { = .Params().At(0).Type() }if .Params().Len() >= 2 { = .Params().At(1).Type() }return , , "", true }return}
The pages are generated with Goldsv0.7.7-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.