// 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 types

import (
	
	
	
	. 
)

// 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 over
	var  operand

	// 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, &, )

	if isTypes2 && .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 types
	var ,  Type
	if .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 declaration
		var  []*Var
		for ,  := range  {
			if  == nil {
				continue
			}

			// determine lhs variable
			var  *Var
			if ,  := .(*ast.Ident);  != nil {
				// declare new variable
				 := .Name
				 = newVar(LocalVar, .Pos(), .pkg, , nil)
				.recordDef(, )
				// _ variables don't count as new variables
				if  != "_" {
					 = 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 variable
				continue
			}

			if  {
				assert( == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
				.initVar(, &, "range clause")
			} else {
				var  operand
				.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 variables
		if len() > 0 {
			 := .Body.Pos()
			for ,  := range  {
				.declare(.scope, nil /* recordDef already called */, , )
			}
		} else {
			.error(, NoNewVar, "no new variables on left side of :=")
		}
	} else if  != nil /* lhs[0] != nil */ {
		// ordinary assignment
		for ,  := 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 {
				var  operand
				.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"
			}
		}
	} else if  {
		// 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) {
		return Typ[Invalid], Typ[Invalid], , false
	}

	,  := commonUnder(, func(,  Type) *typeError {
		// A channel must permit receive operations.
		if ,  := .(*Chan);  != nil && .dir == SendOnly {
			return typeErrorf("receive from send-only channel %s", )
		}
		return nil
	})
	if  == nil {
		return (.format())
	}

	switch typ := arrayPtrDeref().(type) {
	case *Basic:
		if isString() {
			return Typ[Int], universeRune, "", true // use 'rune' name
		}
		if isInteger() {
			if  != nil && !(go1_22) {
				return ("requires go1.22 or later")
			}
			return , nil, "", true
		}
	case *Array:
		return Typ[Int], .elem, "", true
	case *Slice:
		return Typ[Int], .elem, "", true
	case *Map:
		return .key, .elem, "", true
	case *Chan:
		assert(.dir != SendOnly)
		return .elem, nil, "", true
	case *Signature:
		if !buildcfg.Experiment.RangeFunc &&  != nil && !(go1_23) {
			return ("requires go1.23 or later")
		}
		// check iterator arity
		switch {
		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/71164
			if .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 any
		if .Params().Len() >= 1 {
			 = .Params().At(0).Type()
		}
		if .Params().Len() >= 2 {
			 = .Params().At(1).Type()
		}
		return , , "", true
	}
	return
}